当我尝试在EF4中保存具有父/子关系的实体时,我遇到了问题。有时,子项将在父项之前插入 - 这显然会从引用约束的角度引起问题。这两个表的结构如下:
OrderHeader
- OrderID (PK)
OrderDetails
- OrderID (PK)
- DetailID (PK)
(列数更多,但无关紧要)。
注意:我们不会在OrderDetails.OrderID上公开真正的外键,而是使用触发器强制在Header表中存在Details表的OrderID。公开FK可能是一个快速的解决方案,但在我们的应用程序中,不允许对数据库进行那些类型的更改 - 我们必须处理遗留代码等。
查看设计器生成的.edmx文件中的XML,我注意到它在概念模型(CSDL部分)中创建了一个AssociationSet和Association - 并且使用ReferentialConstraint设置了Association。但是,它不会在SSDL部分中创建AssociateSet或Assocation。似乎只有在FK暴露在数据库中时才会添加这些内容。对于我在数据库中测试过的其他数据库(如AdventureWorks或Northwind),当我从数据库生成模型时,我看到EDMX包含SSDL中的Association和AssociationSet部分。
看来EF忽略了我们在模型中的关联(CSDL),而只是按表名按字母顺序插入 - 所以我们在这种情况下运气不好,因为OrderDetail在OrderHeader之前排序(我们当然不会有权重命名表格在我们的情况下)。如果我在SSDL部分中手动添加相应的AssociationSet和Association,则以正确的顺序进行保存(首先插入Header,然后插入Detail)。但是,无论何时我们进行“从数据库更新模型”,这些手动更改都会消失,因此这不是一个非常实用的解决方案。我已经考虑过在运行时尝试动态修复,但感觉要解决一些应该“正常工作”的事情需要付出很多努力。
我希望有一种方法可以让EF在订购插入内容时遵守CSDL中定义的参照约束和/或关联。
答案 0 :(得分:3)
我想我现在明白了这个问题。你根本没有SSDL关系。当EF生成SQL命令时,它仅使用来自SSDL的信息,因此它不知道CSDL中定义的实体之间的依赖关系。我稍后会验证它,但它看起来像EF架构中的bug /设计缺陷。
你可以做些什么来避免这个错误?在SSDL中手动定义关联集并使用一些better tool(商业)来处理EF设计器和更新映射 - 或者转到EDMX的手动维护,因为设计器仅用于简单的场景。
如果您与Microsoft合作,您还可以将行为报告为MS Connect的错误或将其作为支持票据报告,但请注意,即使您获得解决方案,也需要几个月的时间。
答案 1 :(得分:2)
在听到Ladislav Mrnkka的回答并且我自己没有找到一个“简单”解决方案的运气之后,我提出了另一种解决方案。这需要一些努力,但最终结果在我看来是值得的。
我创建了一个使用IModelTransofmrationExtension.OnBeforeModelSaved()方法的Visual Studio扩展。在该方法中,您将获得EDMX文档XDocument
,并且可以在保存之前根据需要对其进行操作。我利用这个机会扫描CSDL部分中SSDL中不存在的关联和关联集。然后我将这些复制到SSDL部分 - 在将实体/属性名称映射到表/列名称与MSL部分中的数据之后。
这有效地“欺骗”EF认为我们的关联有真正的外键,所以它以正确的顺序执行INSERT。
唯一的缺点是我们团队中编辑模型的每个人都需要安装扩展程序 - 否则他们将无法获得生成的FK关联。幸运的是,我们只有少数人编辑模型,因此这是可以管理的。
答案 2 :(得分:1)
没有改变实际使用FK,不确定你可以做你想要的开箱即用。您是否尝试过将整个插入(以正确的顺序并使用输出子句将ID,如果它们是第二个插入的标识)返回存储过程并让EF调用proc?