entity framework6和SQL Server序列

我正在使用EF6与数据库第一个项目。 我们要求使用序列,这是SQL Server 2012中引入的一个特性(我相信)。

在表上,标识列具有使用以下设置的默认值:

(NEXT VALUE FOR [ExhibitIdentity]) 

之所以使用它,因为我们有两个表来存储不同部门的展览信息,但我们需要在两个表中都具有唯一性,因为它在许多其他共享公用表中用作参考。

我的问题是在entity framework中使用它,我用谷歌搜索但找不到与EF6是否支持它们有关的信息。 我已经尝试在EFdesigner设置为Identity但是在保存时会抱怨零行受到影响,因为它使用scope_identity来查看插入是否成功但是当我们使用序列时,它返回为null。

将其设置为computed会抛出一个错误,说我应该将其设置为identity并将其设置为none会导致它将0作为id值插入并失败。

我是否需要调用函数/过程以获取下一个序列,然后在保存记录之前将其分配给id值?

任何帮助深表感谢。

很明显,你无法通过使用DatabaseGeneratedOption逃离这个catch-22。

如您所建议的,最佳选择是设置DatabaseGeneratedOption.None并在保存新记录之前从序列中获取下一个值(例如,在此问题中 )。 然后将其分配给Id值,然后保存。 这是并发安全的,因为您将是唯一一个从序列中绘制特定值的人(假设没有人重置序列)。

但是,有一个可能的黑客……

一个糟糕的,我应该在这里停止……

EF 6引入了命令拦截器API 。 它允许您在执行命令之前和之后操作EF的SQL命令及其结果。 当然,我们不应该篡改这些命令吗?

好吧……如果我们查看在设置DatabaseGeneratedOption.Identity时执行的insert命令,我们会看到如下内容:

 INSERT [dbo].[Person]([Name]) VALUES (@0) SELECT [Id] FROM [dbo].[Person] WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity() 

SELECT命令用于从数据库中获取生成的主键值,并将新对象的标识属性设置为此值。 这使EF能够在后续插入语句中使用此值,该语句通过同一事务中的外键引用此新对象。

当主键由默认值生成时从序列中获取其值(就像你一样),很明显没有scope_identity() 。 然而,序列的当前值可以通过诸如此类的命令找到

 SELECT current_value FROM sys.sequences WHERE name = 'PersonSequence' 

如果只有我们可以让EF在insert之后执行这个命令而不是scope_identity()

好吧,我们可以。

首先,我们必须创建一个实现IDbCommandInterceptor的类,或者从默认实现DbCommandInterceptorinheritance:

 using System.Data.Entity.Infrastructure.Interception; class SequenceReadCommandInterceptor : DbCommandInterceptor { public override void ReaderExecuting(DbCommand command , DbCommandInterceptionContext interceptionContext) { } } 

我们通过命令将此类添加到拦截上下文中

 DbInterception.Add(new SequenceReadCommandInterceptor()); 

ReaderExecuting命令在command执行之前运行。 如果这是带有标识列的INSERT命令,则其文本类似于上面的命令。 现在我们可以通过获取当前序列值的查询替换scope_identity()部分:

 command.CommandText = command.CommandText .Replace("scope_identity()", "(SELECT current_value FROM sys.sequences WHERE name = 'PersonSequence')"); 

现在命令看起来像

 INSERT [dbo].[Person]([Name]) VALUES (@0) SELECT [Id] FROM [dbo].[Person] WHERE @@ROWCOUNT > 0 AND [Id] = (SELECT current_value FROM sys.sequences WHERE name = 'PersonSequence') 

如果我们运行它,有趣的是:它的工作原理。 在SaveChanges命令之后,新对象已收到其持久的Id值。

我真的不认为这是生产准备。 你必须在插入命令时修改命令,根据插入的实体选择正确的序列,所有这些都是在相当模糊的地方通过脏字符串操作。 而且我不知道如果使用大量并发,您将始终获得正确的序列值。 但谁知道,也许EF的下一个版本将支持这种开箱即用。