我有一个简单的雪花模式,从中生成了我的实体框架模型。
问题是我试图将子实体映射到现有的父实体和/或祖父实体,但它仍然插入它。
我跟着这个:
有趣的是,即使父实体的 EntityState 是“未更改”,实体框架仍会尝试插入它。
架构
CarRepository.Save() 方法
public void Save(Car car)
{
using (DBContext context = new DBContext())
{
// No need to save if it already exists
if ( context.Cars.FirstOrDefault(x => x.RegistrationNumber == car.RegistrationNumber) != null)
{
return;
}
else
{
// Check if the parent POCOs exist in the DB.
Model existingModel = context.Models.FirstOrDefault(x => x.Name == car.Model.Name);
Manufacturer existingManufacturer = context.Manufacturers.FirstOrDefault(x=> x.Name == car.Model.Manufacturer.Name)
Trader existingTrader = context.Traders.FirstOrDefault(x=> x.Name == car.Trader.Name)
TraderCompany existingTraderCompany = context.TraderCompanys.FirstOrDefault(x=> x.Name == car.Trader.TraderCompany.Name)
context.ContextOptions.LazyLoadingEnabled = false;
//Attach to the context if existing in the DB, i.e mark the existing POCOs not to be added the DB
if (existingModel != null)
{
car.Model = existingModel;
Assert.IsTrue(context.ObjectStateManager.GetObjectStateEntry(car.Model).State == EntityState.Unchanged);
}
if (existingManufacturer != null)
{
car.Model.Manufacturer = existingManufacturer;
Assert.IsTrue(context.ObjectStateManager.GetObjectStateEntry(car.Model.Manufacturer).State == EntityState.Unchanged);
}
if (existingTrader != null)
{
car.Trader = existingTrader;
Assert.IsTrue(context.ObjectStateManager.GetObjectStateEntry(car.Trader).State == EntityState.Unchanged);
}
if (existingTraderCompany != null)
{
car.Trader.TraderCompany = existingTraderCompany;
Assert.IsTrue(context.ObjectStateManager.GetObjectStateEntry(car.Trader.TraderCompany).State == EntityState.Unchanged);
}
//Mark the Car for Addition to the DB
context.Cars.AddObject(car);
context.ObjectStateManager.ChangeObjectState(car, EntityState.Added);
//If the POCOs do not exist in the DB mark them for addition
if (existingModel == null)
{
context.ObjectStateManager.ChangeObjectState(car.Model,EntityState.Added);
}
if (existingManufacturer == null)
{
context.ObjectStateManager.ChangeObjectState(car.Model.Manufacturer,EntityState.Added);
}
if (existingTrader == null)
{
context.ObjectStateManager.ChangeObjectState(car.Trader,EntityState.Added);
}
if (existingTraderCompany == null)
{
context.ObjectStateManager.ChangeObjectState(car.Trader.TraderCompany,EntityState.Added);
}
context.SaveChanges();
}
}
}
编辑:
经过几天的修补,我设法想出了一个对我有用的解决方法。
似乎正在传递给 CarRepository.Save() 的 Car 具有某种无法检测到的内部上下文......既然如此,就不可能将其与该上下文分离并将其添加到CarRepository.Save()。为了将其实际添加到此上下文中,我深度/延迟复制 Car 对象及其导航属性(如果存在)。
解决方法
public void Save(Car car)
{
using (DBContext context = new DBContext())
{
// No need to save if it already exists
if ( context.Cars
.Any(x => x.RegistrationNumber == car.RegistrationNumber))
{
return;
}
else
{
//Assign scalar properties to the deep copy
Car carToBeSaved = new Car
{
carToBeSaved.RegistrationNumber = car.RegistrationNumber,
carToBeSaved.Price = car.Price
}
//Car -> Trader -> ...
if(car.Trader != null)
{
Trader existingTrader =
context.Traders
.FirstOrDefault(x => x.Name == car.Trader.Name);
//If exists in DB assign, if not deep copy
carToBeSaved.Trader = existingTrader ??
new Trader
{
Name = car.Trader.Name,
JobTitle = car.Trader.JobTitle
}
//Car -> Trader -> TraderCompany
if(car.Trader.TraderCompany != null)
{
TraderCompany existingTraderCompany =
context.TradersCompanys
.FirstOrDefault(x => x.Name == car.Trader
.TraderCompany
.Name);
//If exists in DB assign, if not deep copy
carToBeSaved.Trader.TraderCompany = existingTraderCompany ??
new TraderCompany
{
Name = car.Trader.TraderCompany.Name,
Address = car.Trader.TraderCompany.Address,
PhoneNumber = car.Trader.TraderCompany.PhoneNumber
}
}
}
//Car -> Model -> ...
if(car.Model != null)
{
Model existingModel =
context.Models
.FirstOrDefault(x => x.Name == car.Model.Name);
//If exists in DB assign, if not deep copy
carToBeSaved.Model = existingModel ??
new Model
{
Name = car.Model.Name
}
//Car -> Model -> Manufacturer
if(car.Model.Manufacturer != null)
{
Manufacturer existingManufacturer =
context.Manufacturers
.FirstOrDefault(x => x.Name == car.Model
.Manufacturer
.Name);
//If exists in DB assign, if not deep copy
carToBeSaved.Model.Manufacturer = existingManufacturer ??
new Manufacturer
{
Name = car.Model.Manufacturer.Name
}
}
}
//Mark the Car for Addition to the DB
context.Cars.AddObject(car);
context.SaveChanges();
}
}
}
如果有人对此有任何想法,请分享。
谢谢。