Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用从XML提要检索的实体框架保存/更新实体的最佳方法是什么?_C#_Xml_Asp.net Mvc_Entity Framework - Fatal编程技术网

C# 使用从XML提要检索的实体框架保存/更新实体的最佳方法是什么?

C# 使用从XML提要检索的实体框架保存/更新实体的最佳方法是什么?,c#,xml,asp.net-mvc,entity-framework,C#,Xml,Asp.net Mvc,Entity Framework,背景: 简单地说,我目前正在使用ASP.NET MVC和实体框架开发一个应用程序,它定期从XML提要中提取数据,并将数据保存到数据库,添加新记录和/或更新现有记录 我目前的方法是检索XML提要(使用XmlReader将XML数据反序列化为从xsd.exe工具创建的类)。然后,我遍历检索到的XML数据集合,创建并创建EF类/实体(通过EF Power Tools和反向工程代码优先方法创建),并将这些新的/更新的实体保存到数据库中 示例 在本例中,我处理的是检索位置。DB有一个位置表和位置类型表,在

背景

简单地说,我目前正在使用ASP.NET MVC和实体框架开发一个应用程序,它定期从XML提要中提取数据,并将数据保存到数据库,添加新记录和/或更新现有记录

我目前的方法是检索XML提要(使用XmlReader将XML数据反序列化为从
xsd.exe
工具创建的类)。然后,我遍历检索到的XML数据集合,创建并创建EF类/实体(通过EF Power Tools和反向工程代码优先方法创建),并将这些新的/更新的实体保存到数据库中

示例

在本例中,我处理的是检索位置。DB有一个
位置
表和
位置类型
表,在
位置类型
位置
之间有一对多关系
Location
Location.LocationTypeId
=
LocationType.LocationTypeId
具有外键约束

我需要验证数据库中是否存在XML位置,因此我首先使用XML提要位置ID检索它:如果为null,则表示我正在处理一个新位置;如果它不是空的,那么我正在处理一个现有的位置,我需要更新它

// LOCATION SERVICE

private void LoadLocations()
{
    // retreive XML location data
    List<locationsLocation> locationsFeed = _xmlFeedRepository.GetLocations().ToList();

    // iterate through each location and save to DB
    foreach (var fl in locationsFeed)
    {
        // get location from DB using XML location feedId
        var location = _locationRepository.GetLocationByFeedId(fl.id);

        if (location == null)
        {
            // add location
            HydrateLocation(ref location, fl);
            _locationRepository.AddLocation(location);
        }
        else
        {
            // update location
            HydrateLocation(ref location, fl);
            _locationRepository.UpdateLocation(location);
        }
    }
}

private void HydrateLocation(ref Location location, locationsLocation fl)
{
    if (location == null)
    {
        // create new location
        location = new Location();
    }

    // get location type
    var locationType = _locationRepository.GetLocationTypeByName(fl.type);

    location.Name = fl.name;
    location.FeedId = fl.id;
    // add existing locationType or create new locationType
    location.LocationType = locationType ?? new LocationType { Name = fl.type };
}   

// LOCATION REPOSITORY

public void AddLocation(Location location)
{
    if (location != null)
    {
        using (var context = new MyDBContext())
        {
            context.Locations.Add(location);
            context.SaveChanges();
        }
    }
}

public void UpdateLocation(Location location)
{
    if (location != null)
    {
        using (var context = new MyDBContext())
        {
            context.Locations.Attach(location);
            context.Entry(location).State = EntityState.Modified;
            context.SaveChanges();
        }
    }
}

public Location GetLocationByFeedId(int feedId)
{
    Location location = null;

    if (feedId > 0)
    {
        using (var context = new MyDBContext())
        {
            location = context.Locations.FirstOrDefault(l => l.FeedId == feedId);
        }
    }
    return location;
}
//位置服务
专用void加载位置()
{
//检索XML位置数据
List locationsFeed=_xmlFeedRepository.GetLocations().ToList();
//遍历每个位置并保存到数据库
foreach(位置中的var fl FEED)
{
//使用XML位置feedId从数据库获取位置
var location=\u locationRepository.GetLocationByFeedId(fl.id);
if(位置==null)
{
//添加位置
水合定位(参考位置,fl);
_locationRepository.AddLocation(位置);
}
其他的
{
//更新位置
水合定位(参考位置,fl);
_locationRepository.UpdateLocation(位置);
}
}
}
专用位置(参考位置,位置位置fl)
{
if(位置==null)
{
//创建新位置
位置=新位置();
}
//获取位置类型
var locationType=\u locationRepository.GetLocationTypeByName(fl.type);
location.Name=fl.Name;
location.FeedId=fl.id;
//添加现有locationType或创建新locationType
location.LocationType=LocationType??新LocationType{Name=fl.type};
}   
//位置存储库
公共无效添加位置(位置)
{
如果(位置!=null)
{
使用(var context=new MyDBContext())
{
context.Locations.Add(位置);
SaveChanges();
}
}
}
public void UpdateLocation(位置)
{
如果(位置!=null)
{
使用(var context=new MyDBContext())
{
上下文。位置。附加(位置);
context.Entry(location).State=EntityState.Modified;
SaveChanges();
}
}
}
公共位置GetLocationByFeedId(int feedId)
{
位置=空;
如果(feedId>0)
{
使用(var context=new MyDBContext())
{
location=context.Locations.FirstOrDefault(l=>l.FeedId==FeedId);
}
}
返回位置;
}
问题/担忧


这是添加/更新具有相关实体(例如添加/更新位置及其locationType)的实体的正确方法吗?有人能推荐一种更好的方法吗?

这个解决方案有一些问题,在@Julierlerman的指导和休眠犀牛的帮助下,我设法找到了这些问题(强烈推荐):

  • 给定初始批量导入的记录数(约20K行),执行
    \u locationRepository.GetLocationByFeedId(fl.id)对于每个XML实体来说都是过火了。我已经完全修改了解决方案,但更好的解决方案是对DB进行一次调用,取出所有位置并将它们存储在内存中,然后使用内存中的集合检查该位置是否已经存在。这同样适用于
    \u locationRepository.GetLocationTypeByName(fl.type)

  • 使用
    location.locationType=locationType??新位置类型{Name=fl.type}
    可能会导致重复记录(因为EF认为locationType是一个新的locationType)。更安全的做法是只设置location实体的locationType外键,例如
    location.LocationTypeId=locationType.LocationTypeId

  • 更好的方法是在存储库中声明上下文的私有实例,并声明一个单独的
    SaveChanges()
    方法,而不是使用
    块将每个对上下文的调用包装在


  • 如果不做这些,我可能会担心将同一实体加载两次到您的上下文中的可能性,这会在您的更新中引发异常。这将是一个真正的问题。你会在哪里看到这种情况发生?i、 你能提供一些更详细的信息吗?假设你做了类似
    var x=context.Location.Single(y=>y.id==id)
    之后,你做了类似
    IEnumerable locs=context.Locations.Where(z=>z.Name.Contains(“a”)的事情;
    ,它再次拉入原始实体-这将抛出DbUpdateException,因为在您的上下文中有多个具有相同密钥的实体。现在我再次查看您的代码,我认为您没有问题,因为您将
    上下文的范围保持在很小的范围内,我不相信拉入同一实体的风险两次。