【问题标题】:Entity Framework ModelBinding实体框架模型绑定
【发布时间】:2011-06-07 15:40:42
【问题描述】:

我已经为这个问题苦苦挣扎了一段时间了。使用 UpdateModel() 时,我似乎无法正确更新实体对象。

我只是不认为这是一个复杂的数据模型。看起来这应该是一个非常普遍的情况。也许我需要在 fluent api 的上下文中添加一些内容来消除此错误,但我无法终生解决。

错误信息

操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。

这是我的模型和上下文:

联系方式:

public class Contact {
    public Contact() {
      this.ContactInformations = new HashSet<ContactInformation>();
    }
    public int ContactId { get; set; }
    [Required]
    public string Firstname { get; set; }
    [Required]
    public string Lastname { get; set; }
    public virtual ICollection<ContactInformation> ContactInformations { get; set; }
  }

联系方式:

public class ContactInformation {
    public int ContactInformationId { get; set; }
    public int ContactTypeId { get; set; }
    public int ContactId { get; set; }
    [Required]
    public string Information { get; set; }
}

数据库上下文:

public class Database : DbContext {

    public Database()
      : base("Contacts") {
    }

    public DbSet<Contact> Contacts { get; set; }
    public DbSet<ContactInformation> ContactInformations { get; set; }
}

联系人。

    public ActionResult Edit(int id, Contact form) {
      var contact = db.Contacts.SingleOrDefault(c => c.ContactId == id);
      UpdateModel(contact);
      db.SaveChanges();
      return RedirectToAction("Index");
}

形成数据

[0] "ContactId"  
[1] "Firstname"    
[2] "Lastname"   
[3] "ContactInformations[0].Index" 
[4] "ContactInformations[0].ContactInformationId" 
[5] "ContactInformations[0].ContactId"    
[6] "ContactInformations[0].Information"    
[7] "ContactInformations[0].ContactTypeId"
[8] "ContactInformations[1].Index" 
[9] "ContactInformations[1].ContactInformationId" 
[10] "ContactInformations[1].ContactId"    
[11] "ContactInformations[1].Information"    
[12] "ContactInformations[1].ContactTypeId"

更新 与我的问题有关的一些有趣细节Here

【问题讨论】:

  • 我的 0.02 美元:不要直接绑定到 EF 实体。使用编辑/查看模型。我知道,这不是您要问的,但这最终会使这个问题变得无关紧要。
  • @Craig Stuntz 我在做任何可以使这段代码正常工作的事情上都没有问题。这真是一个黑客,甚至发布这个问题都令人尴尬。如果我使用视图模型,您如何建议将表单中的 ContactInformation 与正在编辑的联系人的联系信息同步?我愿意接受任何建议。
  • 好吧,在我们走这条路之前,我想到了另一个想法:你在数据库中有级联,级联映射是否进入了你的模型?见:stackoverflow.com/questions/2477872/…
  • @Craig Stuntz 我没有使用任何类型的设计师。我首先使用实体​​框架 4.1 代码,所以我所有的模型对象都只是 poco 类。我可以使用 fluent API,但由于使用了约定,所以到目前为止我还不需要。
  • 好的,但级联问题仍然相关。您的数据库和模型中有级联吗?

标签: c# asp.net-mvc entity-framework ef-code-first


【解决方案1】:

EF 中的关系是一流的实体。因此,当您断开此连接时,您必须 (1) 删除关系并 (2) 删除实体。在这段代码中:

  foreach (var item in needDeleted) {
    //have to use the datacontext directly.  I desperately want this gone!
    db.ContactInformations.Remove(db.ContactInformations.Single(c => c.ContactInformationId == item.ContactInformationId));

    //This will produce the same error as UpdateModel(contact)
    //contact.ContactInformations.Remove(contact.ContactInformations.SingleOrDefault(c => c.ContactInformationId == item.ContactInformationId));
  }

...你做了(1)但不是(2)。

可以做:

  foreach (var item in needDeleted) {
    var ci = contact.ContactInformations.Single(c => c.ContactInformationId == item.ContactInformationId);
    contact.ContactInformations.Remove(ci); // 1
    db.ContactInformations.Remove(ci);      // 2
  }

但是,更常见的方法是在 FK 上放置级联并在模型中显示它。在这种情况下,(1) 将自行工作。

【讨论】:

  • FWIW 我仍然建议使用视图模型,但这只会将这个问题推得更远;你需要按照上面的方法解决它。
  • 首先非常感谢您花时间查看我的代码。我在上面的问题中的代码实际上可以正常工作,这只是 IMO 糟糕的代码。理想情况下,我只想说 UpdateModel(contact) 和 MVC 处理所有必须弄清楚哪些实体已被修改/添加/删除的问题。我讨厌我必须直接访问上下文并且我无法通过对象本身实现删除。似乎很奇怪,使用 EF 您可以轻松地进行 contact.ContactInformation.Add(entity) 而不是 contact.ContactInformation.Remove(entity)。
  • 我在这个答案中的 cmets 涉及您问题中的错误消息。更新关系但不删除对象是我知道可能导致该问题的一件事。我怀疑这就是您在执行 UpdateModel 时发生的情况。模型上的级联应该处理“绒毛”,即使使用 UpdateModel。
  • 所以我没有遵循您建议的解决方案,同时仍然允许我使用 UpdateModel() 调用?
  • 使用 POCO 视图模型并编写一个函数将它们映射到实体上。
猜你喜欢
  • 2013-08-03
  • 2015-06-21
  • 2014-10-21
  • 2011-12-05
  • 1970-01-01
  • 2012-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多