“下一个号码”使用实体框架的场景

发布于 2024-10-15 22:44:00 字数 325 浏览 8 评论 0原文

我一直在使用实体框架,到目前为止我非常喜欢使用它。但到目前为止我所做的一切都假设乐观锁定,这在大多数情况下对我来说效果很好。但是,我有以下场景:

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

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

谢谢,

吉姆·K。

I have been playing with Entity Framework and so far I like using it a lot. But everything I've done so far assumes optimistic locking which works well for me in most cases. However, I have the following scenario:

  1. A SQL Server table with only one row that holds application-wide data
  2. The row contains a column named "NextAvailableNumber"
  3. The Application needs to read the number, increment it by 1, and update it

The above has to guarantee that any competing process has to wait to get a number until the first transaction has completed. Previously we have done this using table locks (since there's only one row), but I would like to know how this should be done using LINQ to Entities?

Thanks,

Jim K.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

表情可笑 2024-10-22 22:44:00

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

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

I think you need to implement this in stored procedure because and use explicit row locking (or table locking as you mentioned). Then you will call that procedure from EF. I don't think that this can be handled from application code unless you are using serializable transaction every time you work with your special table. It can have huge negative impact on application's performance.

We are actually doing something similar but our table contains plenty of rows for different sequences so I'm using stored procedure with row lock and update lock. We first wanted to call this procedure in insert method of our repository but after that I moved it into database and I call my procedure from after insert trigger. The reason for this was to deffer row locking to the time of real insertion to database not to the time of marking the entity for insert in EF context (insert itself and procedure call must be in the same transaction in our case). I modified my EF model so that related property has StoreGeneratedPattern set to computed. After each insert EF will requery DB to get assigned sequence number. The only drawback is that EF will also requery DB after each update of these entities but in our case it already do this because of timestamp. This is still in phase of testing and evaluating so I can still change my mind and reimplement it.

好久不见√ 2024-10-22 22:44:00

我们正在使用另一种解决方案,您可以使用它来避免使用存储过程,特别是如果您像我们一样使用 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

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

There is another solution that we are using, and you can use to avoid to use Store Procedures, specially if you are using EF Code First like us. Code First doesn't support the use of Store Procedures.

The solution is using SqlQuery Method of EF inside the scope of transaction, you have to write a query that first do an update of the next number counter, and then select It . The code will be:

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

The Update will lock the counter and avoid reads from other transactions on it until the transaccion is aborted or commited.

人生百味 2024-10-22 22:44:00

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

Since Entity framework uses optimistic locking, it will throw an exception when the next number is changed by a second process. The most primitive way to counter this situation will be catch the exception and redo the change until the change is successful. [you can add a timeout to this to ensure that the code execution moves forward in the worst case scenario]

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文