据我所知,EF(和EF核心)中没有显式锁定我正在查询的资源的选项,但我经常需要这个功能,而且不想每次需要它时都写选择语句。
因为我只需要在postgres中使用它,并且according to the specFOR UPDATE
是查询中的最后一项,所以我认为实现它最简单的方法是按如下所述获得select语句:In Linq to Entities can you convert an IQueryable into a string of SQL?并附加FOR UPDATE
,然后直接执行它。然而,这将给我一个带有参数占位符的查询,或者不是一个预准备的查询,这意味着执行计划的缓存在postgres上不会真正起作用,所以无论哪种方式都是行不通的。
Linq to SQL有DataContext.GetCommand
方法,但在EF中似乎没有任何等效的方法,特别是EF Core。我还看了EntityFramework.Extended和它们的批处理更新/删除,但由于它们必须将选择语句转换为不同的语句,因此它们需要处理的复杂性比我大得多,所以我希望有一个更简单的解决方案。
- 更新日期:**
如果在描述中还不清楚,我想创建一个扩展方法,如下所示:
public static IList<T> ForUpdate (this IQueryable<T> me)
{
// this line is obviously what is missing for me :)
var theUnderlyingCommand = me.GetTheUnderlyingDbCommandOrSimilar();
theUnderlyingCommand.Text += "FOR UPDATE";
return me.ToList();
}
这样,其他开发人员可以通过Linq使用EF,就像所有其他过程一样,他们可以运行.ForUpdate()
,而不是运行.ToList()
。(For Update特意执行查询,以使实现更容易,而且因为FOR UPDATE
是postgres支持的最后一个选项,所以之后不应该再有任何其他操作)
3条答案
按热度按时间7qhs6swi1#
这是我使用SQLServer的工作(没有测试过的异步方法):
首先,创建一个DbCommandInterceptor(我称为HintInterceptor.cs)
所以在Web.config中注册拦截器类
现在我创建一个名为HintExtension的静态类
仅此而已,我可以在数据库事务中使用,例如:
对不起我的英语,我希望我的例子会有所帮助。
xoshrz7s2#
根据this issue,在ef内核中没有简单的方法来实现锁提示和其他面向数据库的调用
我在我的项目中用MsSQL和ef核心实现了UPDLOCK,方法如下:
我们在数据库事务中使用此方法作为原始SQL调用(提交或回滚后将释放锁):
ttp71kqs3#
@gustavo-rossi-muller的答案很有用,但缺乏线程安全性,因此不能与EF Core提供的async methods(如
DbContext.SaveChangesAsync()
)一起使用,因为没有覆盖ScalarExecutingAsync()
和ReaderExecutingAsync()
。公共静态字段
HintValue
上的[ThreadStatic]
属性对于强制每个线程使用它们自己的变量值HintInterceptor.HintValue
而不是在所有线程之间共享相同的值(又称全局变量)是必需的。Document of interceptor已经发现
拦截器通常是无状态的,这意味着单个拦截器示例可以用于所有DbContext示例。
如果你想在每个
DbContext
的拦截器示例中保留一些状态,你必须:此拦截器是有状态的:它存储最近查询的每日消息的ID和消息文本,以及执行该查询的时间。由于这种状态,我们还需要一个锁,因为缓存要求同一拦截器必须由多个上下文示例使用。
但是我们需要的是针对每个查询命令来控制拦截器的状态,因为我们只需要查询某些带有
FOR UPDATE
后缀的SELECT
命令,而不是针对所有会引起很多语法错误的命令。到目前为止,我们只能通过X1 E6 F1 X向某些查询命令中提供一些额外的信息,然后在X1 E7 F1 X的覆盖中检测由标记添加的注解,以便为这些查询附加X1 M11 N1 X提示。
事实上,该文件已经提供了这样做的例子。
我对该示例进行了修改,以便使用MySQL语法附加
FOR UPDATE
:然后在配置DbContext时插入此拦截器:
最后,我们可以做到:
在EF Core 7中,他们还没有计划实施此查询提示后缀:https://github.com/dotnet/efcore/issues/26042,但另一个名为
linq2db
的linq 2sql表达式翻译器已经完成了这一操作:https://github.com/linq2db/linq2db/issues/1276
https://github.com/linq2db/linq2db/pull/3297
https://github.com/linq2db/linq2db/issues/3905