2

我一直在玩 Entity Framework,到目前为止我非常喜欢使用它。但是到目前为止我所做的一切都假设乐观锁定在大多数情况下对我来说很有效。但是,我有以下情况:

  1. 只有一行包含应用程序范围数据的 SQL Server 表
  2. 该行包含名为“NextAvailableNumber”的列
  3. 应用程序需要读取数字,将其增加 1,然后更新它

以上必须保证任何竞争进程都必须等待获得一个数字,直到第一个事务完成。以前我们使用表锁来完成此操作(因为只有一行),但我想知道如何使用 LINQ to Entities 来完成此操作?

谢谢,

吉姆·K。

4

3 回答 3

1

我们正在使用另一种解决方案,您可以使用它来避免使用存储过程,特别是如果您像我们一样使用 EF Code First。Code First 不支持使用存储过程。

解决方案是在事务范围内使用 EF 的 SqlQuery 方法,您必须编写一个查询,首先更新下一个数字计数器,然后选择 It 。代码将是:

string query = "UPDATE Registre_Counter SET Counter = Counter + 1 WHERE CounterName = @p0 AND Year = @p1;";
query += "select * from Registre_Counter Where CounterName = @p0 AND Year = @p1";

GenericCounter GenericCounter = CoreDBContext.Instance().GenericCounter.SqlQuery(query, new Object[] { _counterName, _year }).SingleOrDefault(); //Updates the counter and return de NextNumber to Use

更新将锁定计数器并避免读取其上的其他事务,直到事务中止或提交。

于 2011-06-01T08:09:30.997 回答
1

我认为您需要在存储过程中实现这一点,因为并使用显式行锁定(或您提到的表锁定)。然后,您将从 EF 调用该过程。我认为这不能从应用程序代码中处理,除非您每次使用特殊表时都使用可序列化事务。它会对应用程序的性能产生巨大的负面影响。

我们实际上正在做类似的事情,但我们的表包含大量不同序列的行,所以我使用带有行锁和更新锁的存储过程。我们首先想在存储库的插入方法中调用此过程,但之后我将其移至数据库中,并在插入触发器之后调用我的过程。这样做的原因是将行锁定延迟到实际插入数据库的时间,而不是标记实体以在 EF 上下文中插入的时间(在我们的例子中,插入本身和过程调用必须在同一个事务中)。我修改了我的 EF 模型,以便相关属性将 StoreGeneratedPattern 设置为计算。每次插入后,EF 将重新查询 DB 以获取分配的序列号。唯一的缺点是 EF 还会在每次更新这些实体后重新查询 DB,但在我们的例子中,由于时间戳,它已经这样做了。这仍处于测试和评估阶段,因此我仍然可以改变主意并重新实现它。

于 2011-02-06T00:38:16.627 回答
0

由于 Entity 框架使用乐观锁定,因此当第二个进程更改下一个数字时,它会抛出异常。应对这种情况的最原始方法是捕获异常并重做更改,直到更改成功。[您可以为此添加超时以确保代码执行在最坏的情况下向前推进]

于 2011-02-05T18:02:47.557 回答