我一直在寻找一段时间试图弄清楚这一点。我正在尝试创建一个包含复合主键的表。密钥的第一部分也是父表的外键。第二部分是在SQL Server上自动生成的。所以,我有一个应该看起来像这样的表:实体框架与部分自动生成的复合关键码有关
ParentId ChildId
-------- -------
1 1
1 2
1 3
2 1
2 2
2 3
2 4
ChildId列在ParentId的上下文中是唯一的。这些值是使用INSTEAD OF INSERT触发器在服务器上自动生成的,以便每个ChildId都有自己的序列。
我的问题是,尽管这在SQL Server和经典的ADO.NET SqlCommand
语句中工作得很好,但实体框架并不想使用它。
如果我设置了childID的列的StoreGeneratedPattern是一个身份则EF生成SQL,看起来像这样:
insert [dbo].[ChildTable]([ParentId], [Name])
values (@0, @1)
select [ChildId]
from [dbo].[ChildTable]
where @@ROWCOUNT > 0 and [ParentId] = @0 and [Id] = scope_identity()
这只是产生一个错误:
System.Data.Entity.Infrastructure.DbUpdateConcurrencyException : Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
----> System.Data.OptimisticConcurrencyException : Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
但是,如果我创建了一个使用基于GUID的密钥测试表,并将StoreGeneratedPattern设置为Identity,然后生成的SQL如下所示:
declare @generated_keys table([Id] uniqueidentifier)
insert [dbo].[GuidTable]([Name])
output inserted.[Id] into @generated_keys
values (@0)
select t.[Id]
from @generated_keys as g join [dbo].[GuidTable] as t on g.[Id] = t.[Id]
where @@ROWCOUNT > 0
而我的应用程序中的实体更新为SQL Server生成的GUID的值。
因此,这表明该列不必是一个IDENTITY列,以便实体框架获取值,但是,因为它使用逻辑表inserted
,ChildId的值不会是值它被触发器改变了。此外,inserted
表不能更新操作应用于它将值推回到触发器内(试图说,“逻辑表INSERTED和DELETED不能更新。”)
我觉得我已经有些人在这里支持自己到了一个角落,但在我重新思考设计之前,是否有任何方法通过Entity Framework将ChildId值返回到应用程序中?