【问题标题】:Error in creation of a new Entity (FK constraint issue)创建新实体时出错(FK 约束问题)
【发布时间】:2012-07-24 22:47:40
【问题描述】:

我有点……奇怪的问题。保存与另一个实体具有 * 到 1 关系的新创建实体时出现错误。有点难以解释,但设置如下:

(注意:我使用的是 MVC 2 - 实体框架 4)

我的实体设置如下(为了便于阅读,替换了名称,但结构如所述): 我们公司有一些经理。 (tblManagers) 每个经理拥有未定义数量的 Stores (tblStores)。每个商店都有未定义数量的设备 (tblEquipment)。 所以我的DataModel如下:

(tblManagers) 1* (tblStores) 1* (tblEquipment)

这个设置是有效的,因为我们已经有很多数据了(来自导出旧的 Access 文件)。

在创建新设备时,您显然必须选择它所属的商店。将下拉列表中选择的值(Store 的 ID)传递给 HttpPost 方法,该方法执行以下代码:

db 是我的数据库上下文变量

myNewItem.tblStore = db.tblStores.Single(x => x.Id == store_id_from_dropdown);

db.tblEquipments.AddObject(myNewItem);

db.SaveChanges();

在我看来这是有效的代码。 Resharper 没有发现任何问题,也没有编译错误(甚至警告)。但是,在运行代码时,我遇到了以下异常(在 db.SaveChanges() 上抛出):

Entities in 'CMT_DevEntities.tbl_Stores' participate 
in the 'tblManagerstblStores' relationship. 
0 related 'tblManager' were found. 
1 'tblManager' is expected.

我不知道为什么它甚至会查看 tblManager,因为我的代码中没有引用它。我知道这与经理和他们的商店之间的关系有关,但我不明白为什么

这是让我困惑的部分:

  • 查看myNewItem 的调试值时,我可以看到商店已添加到实体中。我什至可以检查 Store 的 tblManager 属性,它是正确的 tblManager。因此,这确认了数据库中的一切正常(如果没有经理,商店甚至都不存在)。
  • 我实际上遗漏了一些代码。设备中有一个完全相同的导航属性(假设是供应商。供应商又具有国家/地区的导航属性。关系完全相同)。我没有得到这个错误。只有商店/经理一个。

我可能遗漏了一些东西,也许是一些非常简单的东西。无论哪种方式,我都不知道为什么会这样。

所以我的问题是:给定由 MVC 中的 ModelBinder 创建的实体和导航属性的 (int) ID,我如何将新实体添加到数据库中?

【问题讨论】:

  • 不确定 EF,我认为是 4 - 然后先找出来。
  • 确认是 4。更新帖子。
  • db.tblStores.Single(...)db.tblEquipments.AddObject(...) 真的发生在 db 的同一个实例上吗?
  • 代码是精确的复制粘贴。该函数只有一个 using(var db = ....) 块,上面的 sn-p 是 using() 块的内容。
  • 如果你使用db.tblStores.Include("tblManager").Single(...)会发生什么?那么错误会消失吗?

标签: c# asp.net-mvc-2 entity-framework-4


【解决方案1】:

您可以将 Store 的外键 ID 添加到您的 Equipment 实体 (equipment.StoreId),而不是加载所有 Store 实体。

这将确保 EF 在不加载整个图表的情况下看到新创建的 EquipmentStore 实体之间的关系。

由于您使用的是模型优先方法,因此您可以找到有关如何执行此操作的文档here on MSDN

重要的部分在注释部分:

您可以选择不添加导航属性或外键 通过清除关联结束时实体的属性 导航属性和将外键属性添加到实体复选框。如果只添加一个导航属性, 该关联只能在一个方向上遍历。如果你添加 没有导航属性,必须选择添加外键 属性,以便在关联结束时访问实体。 对于多对多 (:) 和一对一 (1:1) 关联,您不能 将外键添加到实体。有关详细信息,请参阅定义 和管理关系(实体框架)。

您应该在“添加关联”对话框中选中“将外键属性添加到“设备”实体”。 使用外键属性是 Entity Framework 4 中的一项新功能。它会让您的生活变得更轻松。

Here你可以找到更详细的解释。

【讨论】:

  • 嗯,我开始怀疑这是一个隐藏了很长时间的问题。我最初并没有构建这个程序,而之前的那个人有一个诀窍,可以试验不同类型的编码和结构。仍然没有完全解决,但你已经帮助了我很长的路,它会得到解决:) 感谢您的完整解释!
  • 欢迎提出更多问题 :) 外键是 EF 中的一个概念
  • 令人讨厌的部分是结构有效。我已经实现了许多其他页面,并且可以成功使用诸如“myEquimpentItem.Store.Name”之类的东西和类似的东西。我可以保存现有设备的编辑。我只在数据库中创建新设备时遇到这个问题。
  • 哈,经过几个月的努力,我发现了这个问题。在我看来,有些人偷偷地隐藏了一个 HiddenFor(Store.ID),其背后的 ID 完全不正确。 EF 认为我正在尝试添加一个新的 Store(因为它是一个不存在的 ID),这反过来又导致违反了 Store-Manager FK 约束。扁平:1;编码错误的应用程序:186。
【解决方案2】:

您需要正确配置实体: 如果您有两个通过外键链接的实体,那么您需要配置导航属性。示例:

public class Destination
{
    public int DestinationId { get; set; }
    public string Name { get; set; }
    public string Country { get; set; }
    public string Description { get; set; }
    public byte[] Photo { get; set; }
    public List<Lodging> Lodgings { get; set; }
}

public class Lodging
{
     public int LodgingId { get; set; }
     public string Name { get; set; }
     public string Owner { get; set; }
     public bool IsResort { get; set; }
     public decimal MilesFromNearestAirport { get; set; }
     public int DestinationId { get; set; }
     public Destination Destination { get; set; }
}

internal class LodgingConfiguration:EntityTypeConfiguration<Charge>
{
    HasRequired(d=>d.Destination).WithMany(l=>l.Logings).HasForeignKey(d=>d.DestinationId)
}

Loging 的创建类似于:

var loging = new Loging
                 {
                     ...initialize properties...
                     Destination = new Destination{..initialize destination..}
                 }
context.Add(loging);
context.SaveChanges();

【讨论】:

  • 他使用的是ObjectContext和Model-First,而不是DbContext和Code-First,所以他不能使用你的提议。
  • Slauma 是正确的。但是还是感谢您的解释,我确实从您的帖子中学到了一些东西:)
  • 是的,误会了。
猜你喜欢
  • 2011-02-23
  • 2021-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多