oce*_*rer 13 c# sql-server entity-framework-6
我正在使用EF6与数据库第一个项目.我们需要使用序列,这是SQL Server 2012中引入的一个特性(我相信).
在表上,标识列具有使用以下设置的默认值:
(NEXT VALUE FOR [ExhibitIdentity])
Run Code Online (Sandbox Code Playgroud)
之所以使用它,因为我们有两个表来存储不同部门的展览信息,但我们需要在两个表中都具有唯一性,因为它在许多其他共享公用表中用作参考.
我的问题是在实体框架中使用它,我用谷歌搜索但找不到与EF6是否支持它们有关的信息.我曾尝试设置StoreGeneratedPatttern
在EFdesigner
以身份,但在保存时这种抱怨零行了,因为它是用影响scope_identity
,看看如果插入成功,但因为我们使用的序列这回来为空.
将其设置为computed会抛出一个错误,说我应该将其设置为identity并将其设置为none会导致它插入0作为id值并失败.
我是否需要调用函数/过程以获取下一个序列,然后在保存记录之前将其分配给id值?
任何帮助深表感谢.
Ger*_*old 17
很明显,你不能通过玩DatabaseGeneratedOption
s 而逃离这个捕获22 .
如您所建议的,最佳选择是在保存新记录之前设置DatabaseGeneratedOption.None
并从序列中获取下一个值(例如,在此问题中).然后将其分配给Id值,然后保存.这是并发安全的,因为您将是唯一一个从序列中绘制特定值的人(假设没有人重置序列).
但是,有一个可能的黑客......
一个糟糕的,我应该在这里停止......
EF 6引入了命令拦截器API.它允许您在执行命令之前和之后操作EF的SQL命令及其结果.当然,我们不应该篡改这些命令吗?
好吧......如果我们看一下DatabaseGeneratedOption.Identity
设置时执行的插入命令,我们会看到如下内容:
INSERT [dbo].[Person]([Name]) VALUES (@0)
SELECT [Id]
FROM [dbo].[Person]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
Run Code Online (Sandbox Code Playgroud)
该SELECT
命令用于从数据库中获取生成的主键值,并将新对象的标识属性设置为此值.这使EF使用中,通过在同一事务外键参考这个新的对象随后插入语句此值.
如果主键是由默认值生成的,则从序列中获取其值(正如您所做的那样),很明显没有scope_identity()
.然而,序列的当前值可以通过诸如此类的命令找到
SELECT current_value FROM sys.sequences WHERE name = 'PersonSequence'
Run Code Online (Sandbox Code Playgroud)
如果只有我们可以让EF在插入后执行此命令而不是scope_identity()
!
好吧,我们可以.
首先,我们必须创建一个实现IDbCommandInterceptor
或继承默认实现的类DbCommandInterceptor
:
using System.Data.Entity.Infrastructure.Interception;
class SequenceReadCommandInterceptor : DbCommandInterceptor
{
public override void ReaderExecuting(DbCommand command
, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
}
}
Run Code Online (Sandbox Code Playgroud)
我们通过命令将此类添加到拦截上下文中
DbInterception.Add(new SequenceReadCommandInterceptor());
Run Code Online (Sandbox Code Playgroud)
该ReaderExecuting
命令在command
执行之前运行.如果这是INSERT
带有标识列的命令,则其文本类似于上面的命令.现在我们可以scope_identity()
通过获取当前序列值的查询替换该部分:
command.CommandText = command.CommandText
.Replace("scope_identity()",
"(SELECT current_value FROM sys.sequences
WHERE name = 'PersonSequence')");
Run Code Online (Sandbox Code Playgroud)
现在命令看起来像
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')
Run Code Online (Sandbox Code Playgroud)
如果我们运行它,有趣的是:它的工作原理.在SaveChanges
命令之后,新对象已收到其持久的Id值.
我真的不认为这是生产准备.当它是一个插入命令时,你必须修改命令,根据插入的实体选择正确的序列,所有这些都是在一个相当模糊的地方通过脏字符串操作.而且我不知道如果使用大量并发,您将始终获得正确的序列值.但谁知道,也许EF的下一个版本将支持这种开箱即用.
归档时间: |
|
查看次数: |
10659 次 |
最近记录: |