我有一个数据库表和一个相应的实体类(带有更改跟踪代理的POCO),其成员充当计数器:
class MyEntity
{
public virtual int ID { get; set; }
public virtual int Counter { get; set; }
}
我的Web应用程序中有一个函数必须通过ID获取此实体,读取Counter
(然后用于分配给其他对象),递增它并将实体写回数据库,像这样:
public int GetNewCounter(int ID)
{
int newCounter = 0;
using (MyObjectContext ctx = new MyObjectContext())
{
MyEntity ent = ctx.MyEntities.Where(e => e.ID == ID).Single();
++ent.Counter;
newCounter = ent.Counter;
ctx.SaveChanges();
}
return newCounter;
}
// newCounter is now used for other stuff
两个或更多用户可以同时执行此操作(使用相同ID的实体)并且我必须确保他们不读取并使用相同的计数器(因此第二个用户不应该能够在第一个用户将递增的计数器存储回数据库之前获取计数器。
是否可以在读取之前“锁定”实体并在写回计数器更改后释放锁定,然后在其他用户尝试读取同一实体时检查锁定?这是一个合理的模式吗?
我有哪些选项可以使用Entity Framework(EF 4)实现此要求?
我对SQL Server和实体框架中的并发功能和想法非常不熟悉,并希望通过这个特定问题为正确的方向寻求帮助。
提前谢谢!
答案 0 :(得分:1)
我很确定TransactionScope(使用事务)将锁定表,但您可能希望确定这是您想要的(表锁)。你也可以看看ConcurrencyMode =“fixed”,虽然我不确定它能不能让你得到你想要的东西。
答案 1 :(得分:0)
我尝试使用乐观并发的解决方案,并通过将ConcurrencyMode
设置为fixed
Counter
MyEntity
属性来回答ThatSteveGuy在edmx模型文件中。
我很高兴看到有人可以查看这个,因为我不知道这是一个很好的解决方案,还是有更简单的方法。
public int GetNewCounter(int ID)
{
int newCounter = 0;
using (MyObjectContext ctx = new MyObjectContext())
{
MyEntity ent = ctx.MyEntities.Where(e => e.ID == ID).Single();
int iRetries = 0;
bool success = false;
do
{
try
{
++ent.Counter;
newCounter = ent.Counter;
ctx.SaveChanges();
success = true;
}
catch (OptimisticConcurrencyException)
{
ctx.Refresh(RefreshMode.StoreWins, ent);
++iRetries;
if (iRetries == 3) // give up after 3 retries
throw;
}
} while (!success);
}
return newCounter;
}