Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/86.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将原始SQL“转换”为纯实体框架_C#_Sql_Sql Server_Entity Framework_Thread Safety - Fatal编程技术网

C# 将原始SQL“转换”为纯实体框架

C# 将原始SQL“转换”为纯实体框架,c#,sql,sql-server,entity-framework,thread-safety,C#,Sql,Sql Server,Entity Framework,Thread Safety,我试图通过C&Entity框架执行一个数据库操作,在该框架中,我根据表中的列更新一个计数器,并获取插入的值 我需要这是在一行,以保持线程安全 我创建的原始SQL可以工作,但我真的不想留下原始SQL而不是“干净”的EF代码。我将非常感谢你帮我翻译这个 int counter = db.Database.SqlQuery<int>($"update [dbo].[table1] set [Counter] = (case when [Counter] < [Maximum] the

我试图通过C&Entity框架执行一个数据库操作,在该框架中,我根据表中的列更新一个计数器,并获取插入的值

我需要这是在一行,以保持线程安全

我创建的原始SQL可以工作,但我真的不想留下原始SQL而不是“干净”的EF代码。我将非常感谢你帮我翻译这个

int counter = db.Database.SqlQuery<int>($"update [dbo].[table1] set [Counter] = (case when [Counter] < [Maximum] then [Counter] + 1  else [Minimum] end) output inserted.Counter Where Id = {myId}").First();

EF LINQ查询仅为SELECT查询。在没有SQL的情况下,您唯一可以做的就是运行查询、保存对实体的更改和范围事务。而且,如果没有输出子句或锁提示,至少在SQLServer中无法实现您想要的功能

一个常见的误解是,使用隔离级别的事务将在这里工作。但不会。当您读入可序列化事务时,您将共享的S锁放在满足查询谓词的行和范围上,并在整个事务中保持这些锁。由于这些是共享锁,两个可序列化事务可以读取同一行。然后,如果其中一个事务试图将共享锁转换为排他锁以更新行,则另一个事务将阻止它。如果两者都尝试更新,将发生死锁

因此,您可以将代码放在一个循环中,捕捉并重试死锁,但这在高频事务中并不可取,死锁将毁掉整个事务,因此循环可能需要重试许多其他语句。所以比这里使用的更新…输出模式要糟糕得多

当然,更好的模式是使用多个对象。因为即使使用UPDATE…OUTPUT,一次也只有一个事务可以生成值,而其他会话将等待该事务提交,直到它们能够生成值。对于序列,生成是非事务性的,多个会话可以生成值,而不会阻塞彼此的事务


在这里,最好将该逻辑包装到存储过程中,然后从DbContext上的函数调用该逻辑。

创建一个存储过程,然后用参数从db_entity调用过程

你可以通过教程自学-其实并不难:而且这些天的文档质量很高,使用也很方便:@johnB谢谢你的回复。我知道如何与EF一起工作,并且在这个项目中广泛使用它,我在这个特定的查询中遇到了麻烦,在我已经看过的视频链接或文档中,我没有看到答案。我对EF的认识还不够标准,但是我可以给你一些一般的建议。这可能根本不可能做到。EF和SQL是从完全不同的基本假设中设计/优化的。有一次,由于otuside的限制,我不得不使用stringconnaction构建一个查询字符串。这是将签入的数组放入其中的唯一方法。幸运的是,该字符串不是直接来自用户输入,而是通过switch…case块进行过滤的。它看起来并不漂亮,但非常好。FWIW,即使这一行也不是线程安全的,因为上下文不是。我认为在事务范围上设置可序列化隔离级别应该可以在没有显式锁提示的情况下完成工作。你是对的,我没有意识到第一个锁是共享的。您的更新非常有用,谢谢。