开发者

How to safely increment a counter in Entity Framework

开发者 https://www.devze.com 2023-02-16 07:38 出处:网络
Let\'s say I have a table that tracks the number of times a file was downloaded, and I expose that table to my code via EF.When the file is downloaded I want to update the count by one.At first, I wro

Let's say I have a table that tracks the number of times a file was downloaded, and I expose that table to my code via EF. When the file is downloaded I want to update the count by one. At first, I wrote something like this:

var fileRecord = (from r in context.Files where r.FileId == 3 select r).Single();
fileRecord.Count++;
context.SaveChanges();

But then when I examined the actual SQL that is generated by these statements I noticed that the incrementing isn't happening on the DB side but instead in my memory. So my program reads the value of the counter in the database (say 2003), performs the calculation (new value is 2004) and then explicitly updates the row with the new Count value of 2004. Clearly this isn't safe from a concurrency perspective.

I was hoping the query would end up looking instead like:

UPDATE Files SET Count = Count + 1 WHERE FileId=3

Can anyone suggest how I might accomplish this? I'd prefer not to lock the row before the read and then unlock after the update because I'm afraid of blocking reads by other users (unless there is someway to lock a row only for writes but not block reads).

I also looked at doing a Entity SQL command but it appears Entity SQL doesn't suppo开发者_如何学编程rt updates.

Thanks


You're certainly welcome to call a stored procedure with EF. Write a sproc with the SQL you show then create a function import in your EF model mapped to said sproc.


You will need to do some locking in order to get this to work. But you can minimise the amount of locking.

When you read the count and you want to update it, you must lock it, this can be done by placing the read and the update inside a transaction scope. This will protect you from race conditions.

When you read the value and you just want to read it, you can do this with a transaction isolation level of ReadUncommited, this read will then not be locked by the read/write lock above.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号