【发布时间】:2016-06-23 06:57:35
【问题描述】:
据我了解,在 EF(和 EF Core)中没有选项可以显式锁定我正在查询的资源,但我会经常需要这个功能,而且我真的不想摔倒回到每次我需要它时编写选择语句。
因为我只需要它用于 postgres 并且 according to the spec FOR 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 及其批量更新/删除,但由于他们必须将 select 语句转换为不同的语句,因此他们需要处理比我更复杂的语句,因此我希望有一个更简单的解决方案。
更新:
如果描述不清楚,我想创建一个这样的扩展方法:
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 用于所有其他过程,而不是运行 .ToList(),而是运行 .ForUpdate()。 (对于 Update 执行查询是为了让实现更容易,也因为 FOR UPDATE 是 postgres 支持的最后一个选项,之后应该不会再有其他任何东西了)
【问题讨论】:
-
EFCore 的主要方法是乐观并发而不是锁定,即使用某个列作为并发标记(或行版本)以确保该行在被读取后没有更新。请注意,目前 Npgsql 提供程序不支持此功能,但可能很快就会支持 (github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/…)。
SELECT FOR UPDATE似乎需要在 EFCore 级别上付出很多努力,所以我怀疑它是否会很快完成,但请尝试向他们提出问题。 -
如果你只是想执行你自己的原始 SQL,你可以在其中追加
FOR UPDATE,EFCore 提供了FromSql方法,或者你可以下拉到 ADO.NET 并做任何你想做的事情想要(这里有一篇好文章:elanderson.net/2016/04/execute-raw-sql-in-entity-framework-core) -
@ShayRojansky 我已经更新了这个问题,因为它可能不够清楚。我知道我可以执行原始 SQL,但我不想在我的应用程序的其余部分处理原始 SQL - 不过,我可以使用专用且经过良好测试的扩展方法来处理它。
-
我有一个事务,但我想在我的所有表上读取,除了一个
-
@GertArnold 如果两个并发操作读取一个项目并稍后尝试更新它,则可序列化事务的工作方式完全不同,其中一个操作将简单地失败 - 但是,如果我已读取提交(或可序列化)并且都用
FOR UPDATE阅读我得到了预期的结果,没有任何问题
标签: entity-framework postgresql entity-framework-core npgsql