在实体框架中以事务方式获取或创建数据库对象
我正在使用 Entity Framework 4.1,并且有一个看似简单的要求:我想通过唯一键获取一个实体,或者如果它尚不存在,则创建它:
var user = db.Users.SingleOrDefault(u => u.Sid == sid);
if (user != null)
return user;
user = new User(sid);
db.Users.Add(user);
通常这工作正常,但是当我运行一堆时一起测试(使用 MSTest),其中之一始终失败,并显示“序列包含多个元素”。当我单独运行该测试时,它工作得很好。
问题似乎很明显:多个线程同时调用上述代码,每个线程创建一个新的用户行。但解决办法是什么?
当然,正确的解决方案是事务,但我就是无法让它发挥作用。如果我启动一个普通的 DbTransaction,EF 将不会使用它。如果我使用 TransactionScope,它要么没有效果(发生相同的错误),要么 EF 尝试启动分布式事务但失败,即使我遵循 有关首先打开连接的建议。
这确实令人沮丧,因为对于普通的旧 SQL 来说,这是一件非常琐碎的事情:开始事务、SELECT、INSERT、提交事务。我怎样才能让它在 EF 中工作?它不必使用事务——无论它如何工作。
I'm using Entity Framework 4.1 and have a seemingly simple requirement: I want to either get an entity by a unique key, or if it doesn't already exist, create it:
var user = db.Users.SingleOrDefault(u => u.Sid == sid);
if (user != null)
return user;
user = new User(sid);
db.Users.Add(user);
Normally this works fine, but when I run a bunch of tests together (using MSTest) one of them consistently fails with "Sequence contains more than one element". When I run that test by itself it works fine.
The problem seems obvious: multiple threads are calling the above code concurrently and each create a new User row. But what is the solution?
The proper solution is a transaction, of course, but I just cannot get it to work. EF won't use a normal DbTransaction if I start one. If I use a TransactionScope it either has no effect (the same error occurs) or EF tries and fails to start a distributed transaction, even if I follow the advice about opening a connection first.
This is really frustrating, because it is such a trivial thing to do with plain old SQL: begin transaction, SELECT, INSERT, commit transaction. How can I get this to work in EF? It doesn't have to be using transactions - whatever makes it work.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您的数据库对
Sid
有UNIQUE
约束,第一个语句(唯一可能导致您描述的错误的语句)将永远不会失败。是吗?它应该。这是确保sid
真正全局唯一的唯一方法。The first statement (the only one which could cause the error you describe) will never fail if your DB has a
UNIQUE
constraint onSid
. Does it? It should. That's the only way to make sure that thesid
is truly, globally unique.