【问题标题】:How to update complex model in ASP.NET MVC 3如何在 ASP.NET MVC 3 中更新复杂模型
【发布时间】:2012-02-10 00:16:47
【问题描述】:

我正在尝试在单个视图中更新复杂模型。 我正在使用 ASP.NET MVC3、带有代码优先的实体框架、工作单元、通用存储库模式.. 但是当我尝试更新模型时,我想出了这个错误:

发生参照完整性约束冲突:定义参照约束的属性值在关系中的主体对象和依赖对象之间不一致。

这是我的简化视图模型:

public class TransactionViewModel
{
     public Transaction Transaction { get; set; }
     public bool IsUserSubmitting { get; set; }
     public IEnumerable<SelectListItem> ContractTypes { get; set; }
}

这是我简化的复杂模型,并以它的导航属性为例。 事务与它的所有导航属性都是一对一的关系:

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;
}

问题更加复杂,因为我应该能够在单个视图中编辑 Transaction 对象内任何导航属性中的任何字段(属性)。

【问题讨论】:

    标签: asp.net-mvc entity-framework ef-code-first unit-of-work


    【解决方案1】:

    我认为异常意味着以下:

    定义引用约束的属性值...(这些是Bid 的主键属性 (= Id) 值和外键属性 (= BidId) Transaction的值)

    ...不一致...(=有不同的值)

    ...主体之间... (= Bid)

    ...和依赖... (= Transaction)

    ...关系中的对象。

    因此,如下所示:当 MVC 模型绑定器创建 TransactionViewModel 作为 Edit 操作的参数时,model.Transaction.BidIdmodel.Transaction.Bid.Id 是不同的,例如:

    • model.Transaction.BidId.HasValuetruemodel.Transaction.Bidnull
    • model.Transaction.BidId.HasValuefalsemodel.Transaction.Bid 不是 null
    • model.Transaction.BidId.Value != model.Transaction.Bid.Id

    (第一点可能不是问题。我猜你的情况是2。)

    这同样适用于CurrentStageEvaluation

    可能的解决方案:

    • 在调用存储库的 Update 方法之前将这些属性设置为相同的值 (=hack)
    • TransactionViewModel.Transaction.BidIdTransactionViewModel.Transaction.Bid.Id 绑定到具有相同值的两个隐藏表单字段,以便模型绑定器填充这两个属性。
    • 还为您的内部Transaction 属性(以及Transaction 内部的导航属性)使用一个 ViewModel,它是为您的视图量身定制的,您可以将其适当地映射到控制器操作中的实体。李>

    最后一点要提的是,这条线...

    context.Entry(entityToUpdate).State = EntityState.Modified;
    

    ... 不会将相关对象 (Transaction.Bid) 标记为已修改,因此它不会保存对 Transaction.Bid 的任何更改。您还必须将相关对象的状态设置为Modified

    旁注:如果您没有使用 Fluent API for EF 的任何其他映射,那么您的所有关系都不是一对一而是一对多,因为您有单独的 FK 属性。与 EF 的一对一关系需要共享主键。

    【讨论】:

    • 你完全正确!使用共享主键进行一对一关系并在控制器中手动设置 ID 解决了这个问题。谢谢!
    • 我遇到了类似的问题,我编写了一个所有其他存储库都可以实现的通用基础存储库类。通过确保仅使用相关实体的 ID 而不是整个相关实体的 ID 解决了我的问题。
    • joonho,我有问题。您能帮忙在控制器中手动设置值吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多