假设在发表评论时对博客文章的评论数进行更新:
blogPost.FeedBackCount++;
Enity Framework生成的SQL语句是这样的:
exec sp_executesql N'update [dbo].[blog_Content]
set [FeedBackCount] = @0
where ([ID] = @1)
',N'@0 int,@1 int',@0=16471,@1=1825
这样的更新是不安全的,存在并发问题,假如A与B同时发表评论,得到的是同样的FeedBackCount,在更新时,后一个更新操作会覆盖前一个更新操作的FeedBackCount。
更合理的SQL语句应该是这样的:
exec sp_executesql N'update [dbo].[blog_Content]
set [FeedBackCount] = [FeedBackCount]+1
where ([ID] = @0)
',N'@0 int',@0=1825
但不知在Entity Framework如何实现这样的更新?
stackoverflow上有人提出了同样的问题:How to safely increment a counter in Entity Framework
第一中方式是使用EF中的事物
第二种方式是在EF中使用sql语句。
其他的不太懂了,没用过EF,嘿嘿
如果找到EF的解决方法,就准备用SQL语句
blogPost.FeedBackCount++,这句话执行的同时数据库就更新了?还是最后调用个类似update,merge等方法时才将内存中的实体更新到数据库?直接执行sql吧。呵呵。
SaveChanges()代码被省略...
其实EF也可以不象你的第一条语句那样,只要这样:
//Use Data Annotation
[ConcurrencyCheck]
public int FeedBackCount {get;set;}
//Or Use Fluent API
Property(t=>t.FeedBackCount).IsConcurrencyToken();
这样生成的更新就没有并发问题。当然与我们经典的直接操作Sql的语句还是有点不一样。这两天正在学习,看到有好的解决方案再来。
采用ConcurrencyCheck之后,生成的SQL为:
exec sp_executesql N'update [dbo].[blog_Content]
set [FeedBackCount] = @0
where (([ID] = @1) and ([FeedBackCount] = @2))
',N'@0 int,@1 int,@2 int',@0=16472,@1=1825,@2=16471
这个方法在并发时会造成不能更新
@dudu: 当然了。但是不能更新你就知道FeedBackCount被改变了。所以这个是一个次优选择。
事实上set count = count + 1也并不能保证并发状况。我不知道这是针对EF生成SQL的特例,还是需要解决FackBackCount的问题。如果是解决FackBackCount的并发,建议使用缓存所有”即读即写“字段,使用内部计划任务来更新这些字段。
对,set count = count + 1 不能保证并发更新时能否成功,但是不会造成"脏写"。
要解决的是“脏写”问题