【问题标题】:Using StoreGeneratedPattern.Identity with database-trigger-generated primarykey values not possible?无法将 StoreGeneratedPattern.Identity 与数据库触发器生成的主键值一起使用?
【发布时间】:2012-01-28 13:15:09
【问题描述】:

这个问题与我在这里提出的另一个问题 (Entity Framework 4.2 - How to realize TPT-Inheritance with Database-generated Primarykey Value?) 相关,并且应该简单地澄清一下,我对主题中所述问题的假设是否正确。

问题(详细):

  • 我想使用 EF (4.1) 访问一个已经存在的数据库
  • 数据库对其表的主键值的生成有一些限制(有一个 UDF 采用表名并返回下一个可用 ID)
  • 为了让我自己尽可能简单,我的第一个方法是定义数据库触发器(在插入之前),这些触发器调用 ID 生成 UDF 以在插入新数据行时设置新 ID
  • 然后我将我的 EDM 的 csdl 中相应实体的 StoreGeneratedPattern 属性设置为“Identity”,以便在将新生成的 ID 保存到 DB 后将它们设置在实体对象中

结果是:

当我创建一个新的实体对象,将它添加到 DbContext 并在其上调用 SaveChanges 时,相应的数据行被插入到数据库中,但实体没有使用新的数据库生成的 ID 进行更新。当我尝试一次保存更多时,我意识到了这一点,它们之间有关联(父子),因为子实体的外键属性无法正确设置,因为父实体的新 ID 不知道数据库上下文。

这就是我问上面提到的关于 TPT 继承的问题的原因。

经过几天的研究并尝试了我想到的一切来解决这个问题,我想我意识到这根本行不通。尽管 MSDN 上 StoreGeneratedPattern 枚举的文档和博客中的一些解释表明,应设置 StoreGeneratedPattern.Identity 以检索生成的值,但当数据库在插入新行时生成值时,主键并不适用使用数据库触发器。

在考虑了很长时间之后,这对我来说似乎是完全合乎逻辑的,因为 EF 需要一些标准来检索数据库生成的值,我认为在大多数情况下这将是实体的身份。对于设置为自动增量(或标识列,...)的数据库列,这可能没有问题,因为 DBMS 提供了一些功能来检索最后插入的标识值(例如 MSSQL 中的@@identity)。但是当使用触发器生成一个新的标识值时,EF 显然不知道如何查询新插入的行(我也无法想象任何好的独立于 db 的方法来做到这一点)。

所以我的实际问题是:上面的假设是正确的还是我在这里忽略了一些重要的东西?

提前感谢您对此的任何澄清/启发。

编辑(后续问题):

在阅读了拉迪斯拉夫的回答后,另一个问题出现了:

如果我在 CSDL 中设置 StoreGeneratedPattern,我是否必须在 SSDL 中将其设置为相同的值(反之亦然)? edm 设计器的补丁暗示了这种情况,因为当您在 CSDL 中(通过设计器)更改 StoreGeneratedPattern 时,它会自动同步 SSDL 中的 StoreGeneratedPattern。

【问题讨论】:

    标签: entity-framework-4.1 identity dbcontext database-trigger


    【解决方案1】:

    StoreGeneratedPattern.Identity 应该可以工作。如果在 EF 设计器中设置它,请确保它在 EDMX 文件的 SSDL 和 CSDL 部分中都正确配置(以 XML 格式打开以检查它)。 EF 设计器中存在一个错误,导致仅在 CSDL 中正确设置,因此 SQL 部分不知道插入后必须从数据库中选择新 ID。这个错误在极少数情况下由installing VS 2010 SP1 解决,它肯定应该由special patch 解决。

    【讨论】:

    • 我已经安装了补丁,还尝试了 SSDL 和 CSDL 中 StoreGeneratedPattern 值的各种组合。它们都不适合我。在使用 SQLEXPRESS DB 的测试示例中,发出以下 SQL 语句来查询新 ID:select [id] from [dbo].[ParentEntities] where @@ROWCOUNT > 0 and [id] = scope_identity()。 scope_identity 函数仅适用于标识列,但我没有标识列,因为我在触发器中生成了我的 ID。
    • 是的,CSDL 和 SSDL 中的值必须相同。作为一种解决方法,您可以创建自定义存储过程以插入实体(也可能用于更新和删除),并在存储过程中调用您的 UDF 并返回正确的 ID。
    • 感谢您的回答。您还可以声明一下,StoreGeneratedPattern.Identity 是否与主键列一起仅适用于身份/自动增量列(我想在这种情况下查询生成的 ID 的行为取决于 DBMS 特定的 EF 提供程序)和 没有数据库触发器?
    【解决方案2】:

    我遇到了同样的问题:其中一列设置了触发器。

    但似乎我在使用 VS edmx 设计器时确实遇到了问题(“身份”尚未设置),它帮助手动修复了它(一个模型具有正确的值,但另一个没有)。

    然后我们得到“存储更新、插入或删除语句影响了意外数量的行 (0)。实体可能在加载实体后已被修改或删除。刷新 ObjectStateManager 条目”。按照here

    的指示,这很容易解决

    如果我在 CSDL 中设置 StoreGeneratedPattern,我是否必须将其设置为 SSDL 中的值相同(反之亦然)?

    是的,如果不更改 CSDL 和 SSDL,它似乎无法正常工作

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-31
      • 1970-01-01
      • 2016-03-30
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 2011-10-29
      相关资源
      最近更新 更多