草庐IT

c# - Entity Framework 6 和 SQL Server 序列

coder 2024-05-25 原文

我在数据库优先项目中使用 EF6。我们需要使用序列,这是 SQL Server 2012 中引入的一项功能(我相信)。

在表中,标识列使用以下方式设置了默认值:

(NEXT VALUE FOR [ExhibitIdentity])

这是因为我们有两个表来存储不同部门的展览信息,但我们需要标识在两个表中都是唯一的,因为它随后将用作许多其他共享公用表的引用。

我的问题是在 Entity Framework 中使用它,我用 google 搜索了但找不到太多关于 EF6 是否支持它们的信息。我尝试将 EFdesigner 中的 StoreGeneratedPattern 设置为 Identity 但是在保存时提示零行受到影响,因为它正在使用 scope_identity 查看插入是否成功,但由于我们使用的是序列,因此返回为 null。

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

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

非常感谢任何帮助。

最佳答案

很明显,您无法通过使用 DatabaseGeneratedOption 来逃避这个第 22 条军规。

正如您所建议的,最好的选择是在保存新记录之前设置 DatabaseGeneratedOption.None 并从序列中获取下一个值(例如 this question )。然后赋值给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()

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

当默认情况下从序列中获取其值(如您所做的那样)生成主键时,很明显不存在 scope_identity()。然而,序列有一个当前值,可以通过像

这样的命令找到
SELECT current_value FROM sys.sequences WHERE name = 'PersonSequence'

要是我们能让 EF 在插入之后执行这条命令就好了,而不是 scope_identity()!

好吧,我们可以。

首先,我们必须创建一个实现IDbCommandInterceptor的类,或者继承自默认实现DbCommandInterceptor:

using System.Data.Entity.Infrastructure.Interception;

class SequenceReadCommandInterceptor : DbCommandInterceptor
{
    public override void ReaderExecuting(DbCommand command
           , DbCommandInterceptionContext<DbDataReader> 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 会开箱即用地支持这一点。

关于c# - Entity Framework 6 和 SQL Server 序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24162895/

有关c# - Entity Framework 6 和 SQL Server 序列的更多相关文章

  1. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  2. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  3. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  4. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  5. ruby - 在 Ruby 中比较序列 - 2

    假设我必须(小型到中型)阵列:tokens=["aaa","ccc","xxx","bbb","ccc","yyy","zzz"]template=["aaa","bbb","ccc"]如何确定tokens是否以相同的顺序包含template的所有条目?(请注意,在上面的示例中,应忽略第一个“ccc”,从而由于最后一个“ccc”而导致匹配。) 最佳答案 这适用于您的示例数据。tokens=["aaa","ccc","xxx","bbb","ccc","yyy","zzz"]template=["aaa","bbb","ccc"]po

  6. ruby-on-rails - carrierwave:在序列化动态属性上安装 uploader - 2

    首先,我使用的是rails3.1.3和来自master的carrierwavegithub仓库的分支。我使用after_init钩子(Hook)来确定基于属性的字段页面模型实例并为这些字段定义属性访问器将值存储在序列化哈希中(希望它清楚我是什么谈论)。这是我正在做的事情的精简版:classPage省略mount_uploader命令让我可以访问我想要的属性。但是当我安装uploader时出现错误消息说“nil类的未定义新方法”我在源代码中读到有方法read_uploader和扩展模块中的write_uploader。我如何必须覆盖这些来制作mount_uploader命令使用我的“虚拟

  7. c# - C# 中的 Flatten Ruby 方法 - 2

    我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume

  8. ruby - 可以像在 C# 中使用#region 一样在 Ruby 中使用 begin/end 吗? - 2

    我最近从C#转向了Ruby,我发现自己无法制作可折叠的标记代码区域。我只是想到做这种事情应该没问题:classExamplebegin#agroupofmethodsdefmethod1..enddefmethod2..endenddefmethod3..endend...但是这样做真的可以吗?method1和method2最终与method3是同一种东西吗?还是有一些我还没有见过的用于执行此操作的Ruby惯用语? 最佳答案 正如其他人所说,这不会改变方法定义。但是,如果要标记方法组,为什么不使用Ruby语义来标记它们呢?您可以使用

  9. c# - Ruby 等效于 C# Linq 聚合方法 - 2

    什么是Linq聚合方法的ruby​​等价物。它的工作原理是这样的varfactorial=new[]{1,2,3,4,5}.Aggregate((acc,i)=>acc*i);每次将数组序列中的值传递给lambda时,变量acc都会累积。 最佳答案 这在数学以及几乎所有编程语言中通常称为折叠。它是更普遍的变形概念的一个实例。Ruby从Smalltalk中继承了这个特性的名称,它被称为inject:into:(像aCollectioninject:aStartValueinto:aBlock一样使用。)所以,在Ruby中,它称为inj

  10. 机器学习——时间序列ARIMA模型(四):自相关函数ACF和偏自相关函数PACF用于判断ARIMA模型中p、q参数取值 - 2

    文章目录1、自相关函数ACF2、偏自相关函数PACF3、ARIMA(p,d,q)的阶数判断4、代码实现1、引入所需依赖2、数据读取与处理3、一阶差分与绘图4、ACF5、PACF1、自相关函数ACF自相关函数反映了同一序列在不同时序的取值之间的相关性。公式:ACF(k)=ρk=Cov(yt,yt−k)Var(yt)ACF(k)=\rho_{k}=\frac{Cov(y_{t},y_{t-k})}{Var(y_{t})}ACF(k)=ρk​=Var(yt​)Cov(yt​,yt−k​)​其中分子用于求协方差矩阵,分母用于计算样本方差。求出的ACF值为[-1,1]。但对于一个平稳的AR模型,求出其滞

随机推荐