我正在使用ASP.NET MVC3,Entity Framework with Code first,工作单元,通用存储库模式..
但是当我尝试更新模型时,我想出了这个错误:
发生了引用完整性约束违规:定义引用约束的属性值在关系中的主体和从属对象之间不一致.
这是我的简化视图模型:
public class Transactionviewmodel { public Transaction Transaction { get; set; } public bool IsUserSubmitting { get; set; } public IEnumerable<SelectListItem> ContractTypes { get; set; } }
这是我的简化复杂模型,并作为其导航属性之一的示例.
Transaction与其所有导航属性具有一对一的关系:
public class Transaction { [Key] public int Id { get; set; } public int CurrentStageId { get; set; } public int? BidId { get; set; } public int? EvaluationId { get; set; } public virtual Stage CurrentStage { get; set; } public virtual Bid Bid { get; set; } public virtual Evaluation Evaluation { get; set; } } public class Bid { [Key] public int Id { get; set; } public string Type { get; set; } public DateTime? PublicationDate { get; set; } public DateTime? BidopeningDate { get; set; } public DateTime? ServiceDate { get; set; } public string ContractBuyerComments { get; set; } public string BidNumber { get; set; } public DateTime? ReminderDate { get; set; } public DateTime? SubmitDate { get; set; } }
使用相同的视图模型,我能够创建一个事务对象,它将像这样填充数据库.
Id:1,CurrentStageId:1,BidId:1,EvaluationId:1
但是,当我尝试更新这些导航属性中的属性时,此行会在控制器中导致错误:
[HttpPost] public ActionResult Edit(Transactionviewmodel model) { if (ModelState.IsValid) { -> unitOfWork.TransactionRepository.Update(model.Transaction); unitOfWork.Save(); return RedirectToAction("List"); } }
在通用存储库中:
public virtual void Update(TEntity entityToUpdate) { -> dbSet.Attach(entityToUpdate); context.Entry(entityToUpdate).State = EntityState.Modified; }
解决方法
定义引用约束的属性值…(这些是Bid的主键属性(= Id)值和Transaction的外键属性(= BidId)值)
……不一致……(=有不同的值)
……校长之间…(=投标)
……和依赖…(=交易)
……关系中的对象.
因此,它看起来如下所示:当MVC模型绑定器创建Transactionviewmodel作为Edit操作的参数时,model.Transaction.BidId和model.Transaction.Bid.Id是不同的,例如:
> model.Transaction.BidId.HasValue为true但model.Transaction.Bid为null
> model.Transaction.BidId.HasValue为false但model.Transaction.Bid不为null
> model.Transaction.BidId.Value!= model.Transaction.Bid.Id
(第一点可能不是问题.我的猜测是你有情况2.)
这同样适用于CurrentStage和Evaluation.
可能的解决方案:
>在调用存储库的Update方法之前,将这些属性设置为相同的值(= hack)
>将Transactionviewmodel.Transaction.BidId和Transactionviewmodel.Transaction.Bid.Id绑定到具有相同值的两个隐藏表单字段,以便模型绑定器填充这两个属性.
>还可以使用viewmodel作为内部Transaction属性(以及Transaction内部的导航属性),该属性是根据您的视图定制的,您可以将其适当地映射到控制器操作中的实体.
最后一点要提到的是这条线……
context.Entry(entityToUpdate).State = EntityState.Modified;
…不会将相关对象(Transaction.Bid)标记为已修改,因此不会保存Transaction.Bid的任何更改.您还必须将相关对象的状态设置为“已修改”.
附注:如果您没有使用Fluent API for EF的任何其他映射,那么您的所有关系不是一对一的,而是一对多的,因为您有单独的FK属性.与EF的一对一关系需要共享主键.