【发布时间】:2013-10-01 23:03:24
【问题描述】:
背景:
简单地说,我目前正在开发一个使用 ASP.NET MVC 和实体框架的应用程序,它定期从 XML 提要中提取数据并将数据保存到数据库中,添加新记录和/或更新现有记录。
我当前的方法是检索 XML 提要(使用 XmlReader 将 XML 数据反序列化为从 xsd.exe 工具创建的类)。然后,我遍历检索到的 XML 数据集合,创建和水合 EF 类/实体(通过 EF Power Tools 和逆向工程师代码优先方法创建)并将这些新的/更新的实体中的每一个保存到数据库中。
示例
在此示例中,我正在处理检索位置。 DB有一个Location表和一个LocationType表,LocationType和Location之间是一对多的关系。 Location 对 Location.LocationTypeId 有一个外键约束 = LocationType.LocationTypeId。
我需要验证 XML 位置是否存在于数据库中,所以我首先使用 XML 提要位置 ID 检索它:如果它为空,我正在处理一个新位置;如果它不为空,那么我正在处理一个现有位置,我需要更新它。
// 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;
}
问题/疑虑
这是添加/更新具有相关实体的实体的正确方法,例如,添加/更新位置及其 locationType?任何人都可以建议这样做的首选方式吗?
【问题讨论】:
-
如果不摆弄这个,我可能会担心将同一实体两次加载到您的上下文中的可能性,这会在您的更新中引发异常。
-
这将是一个真正的问题。你会在哪里看到这种情况发生?也就是说,你能提供更多细节吗?
-
假设您执行
var x = context.Location.Single(y => y.id == id)之类的操作稍后,您执行IEnumerable<Location> locs = context.Locations.Where(z => z.Name.Contains("a");之类的操作,这会再次拉入原始实体 - 这将引发 DbUpdateException,因为您将拥有多个具有相同键的实体在你的上下文中。现在我再次查看您的代码,我认为您没问题,因为您将context的范围保持在较小的范围内,我认为不会有两次拉入同一个实体的风险。
标签: c# xml asp.net-mvc entity-framework