我对EF相对较新,我有以下问题,即使我现在一直在寻找答案,但我似乎无法找到我需要的答案。
我有一个实现,其中包括通用数据存储库,业务存储库和使用MVC的表示层。
当我检索实体的值时,我还包括子导航属性,如下所示:
public EngineModel GetEngineModelById(ref string errorStr, int engineModelId)
{
try
{
return this.GetSingle(
emd => emd.emdId.Equals(engineModelId),
emd => emd.EngineManufacturer,
emd => emd.EngineConfiguration,
emd => emd.FuelType); //include related entitie(s)
}
catch (Exception ex)
{
errorStr = ex.Message;
return null;
}
}
每当我对此Engine Model实体执行更新并修改上述3个相关entite中的任何一个上的外键时,都会出现参照完整性约束违规错误。
在阅读了很多关于它之后,我理解为什么会发生错误。让我们说当我检索上面的数据时,我得到一个ID为3的引擎配置,现在我尝试将其更新为4.我的emd.EngineConfigurationId将为4,但EngineConfiguration实体中的主键仍然是a 3然后实体框架将抛出错误。
我如何获得这个?我读到将EngineConfiguration相关实体设置为null或将EngineConfiguration中的PK设置为与我的FK中的引擎配置中的引擎配置相同的值,然后我在通用数据存储库中调用我的更新例程将起作用,但在我的情况下它永远不会。
这是我的通用更新例程:
public virtual void Update(params T[] items)
{
using (var context = new Engine_AngelEntities())
{
foreach (T item in items)
{
context.Entry(item).State = System.Data.EntityState.Modified;
}
context.SaveChanges();
}
}
到目前为止,我发现的唯一一个问题是当我第一次在上面的第一个例程中提取数据时,不会检索相关的实体。这样,我可以更新任何我想要的东西,我永远不会得到错误。每次我都包含一个相关的实体,并尝试更新我的主实体中指向任何相关实体的外键值,我收到错误。
有没有办法像我在上面的第一个例程中那样检索我的相关实体,但是在更新期间,以某种方式排除导航属性,以便唯一获得更新的实体实际上是我的主要实体?
我希望我的问题有道理,如果我对我的问题造成任何疑惑,我很抱歉...
更新1: 这是代码: 控制器:
[Authorize(Roles = "Engines")]
[POST("{engineModelID:int}/edit")]
public ActionResult Edit(EngineModel updatedEngineModel)
{
Validate(updatedEngineModel);
if (!ModelState.IsValid)
return View(updatedEngineModel);
string error = "";
var engineModel = engineModelRepository.GetEngineModelById(ref error, updatedEngineModel.emdId);
if (!string.IsNullOrEmpty(error))
this.Alert(error, AlertEnum.Error);
if (engineModel == null)
{
this.Alert("Engine Configuration not found", AlertEnum.Info);
return RedirectToAction("List");
}
engineModel = SetengineModel(engineModel, updatedEngineModel);
if (Request.Form["new"] != null && Request.Form["new"] == "on")
return New(engineModel);
engineModelRepository.UpdateEngineModel(ref error, engineModel);
if (!string.IsNullOrEmpty(error))
this.Alert(error, AlertEnum.Error);
else
this.Alert("Engine Configuration updated", AlertEnum.Success);
return RedirectToAction("List");
}
private EngineModel SetengineModel(EngineModel engineModel, EngineModel updatedEngineModel)
{
engineModel.emdModel = updatedEngineModel.emdModel;
engineModel.emdEngineMfgrId = updatedEngineModel.emdEngineMfgrId;
engineModel.EngineConfiguration = null;
engineModel.emdEngineConfigurationId = updatedEngineModel.emdEngineConfigurationId;
engineModel.emdFiringSequence = updatedEngineModel.emdFiringSequence;
engineModel.emdFuelTypeId = updatedEngineModel.emdFuelTypeId;
engineModel.FuelType = updatedEngineModel.FuelType;
engineModel.emdWeight = updatedEngineModel.emdWeight;
engineModel.emdBore = updatedEngineModel.emdBore;
engineModel.emdStroke = updatedEngineModel.emdStroke;
engineModel.emdCompressionRatio = updatedEngineModel.emdCompressionRatio;
engineModel.emdElectronics = updatedEngineModel.emdElectronics;
engineModel.emdEGR = updatedEngineModel.emdEGR;
engineModel.emdTurbo = updatedEngineModel.emdTurbo;
engineModel.emdTurboCompounder = updatedEngineModel.emdTurboCompounder;
engineModel.emdHPRange = updatedEngineModel.emdHPRange;
engineModel.emdTorqueRange = updatedEngineModel.emdTorqueRange;
engineModel.emdTurboCompounder = updatedEngineModel.emdTurboCompounder;
engineModel.emdOilCapacity = updatedEngineModel.emdOilCapacity;
engineModel.emdLastUpdateUser = "me"; // TODO: Somethign around logged in user
engineModel.emdLastUpdateDateTime = DateTime.Now;
return engineModel;
}
业务对象层中的相关方法:
public EngineModel GetEngineModelById(ref string errorStr, int engineModelId)
{
try
{
return this.GetSingle(
emd => emd.emdId.Equals(engineModelId),
emd => emd.EngineManufacturer,
emd => emd.EngineConfiguration,
emd => emd.FuelType); //include related entitie(s)
}
catch (Exception ex)
{
errorStr = ex.Message;
return null;
}
}
public void UpdateEngineModel(ref string errorStr, params EngineModel[] engineModel)
{
try
{
this.Update(engineModel);
}
catch (Exception ex)
{
errorStr = ex.Message;
}
}
通用数据存储库中的相关方法:
public virtual T GetSingle(Func<T, bool> where,
params Expression<Func<T, object>>[] navigationProperties)
{
T item = null;
using (var context = new Engine_AngelEntities())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
item = dbQuery
.AsNoTracking() //Don't track any changes for the selected item
.FirstOrDefault(where);//Apply where clause
}
return item;
}
public virtual void Update(params T[] items)
{
using (var context = new Engine_AngelEntities())
{
foreach (T item in items)
{
context.Entry(item).State = System.Data.EntityState.Modified;
}
context.SaveChanges();
}
}