[英]Two nested Entity Framework contexts, sharing a transaction
我有看起来像下面的示例的代码。 由于需要通过SP完成一些数据库伪造,并且其中包含一个保存更改,因此涉及到显式事务。 (异常处理,回滚等。省略):
void OuterMethod(MyDatbase context)
{
using(var dbTrans = context.Database.BeginTransaction())
{
// some stuff, the save puts the data where the SP can see it
Stuff(context);
context.SaveChanges();
// now some SP stuff
context.Database.ExecuteSqlCommand(@"spFoo", params);
// more stuff
MoreStuff(context);
AlmostUnrelatedCode(context);
context.SaveChanges();
dbTrans.Commit();
}
}
现在,方法AlmostUnrelatedCode()
-仅与上述过程略相关-在99%的时间中需要一个不错的,快速的,一次性的只读上下文。 我有一家工厂,可以在需要时为我提供合适的服务。 从上面那个块的中间被调用的时间的1%。
MyDatabase localReadOnlyContext;
void AlmostUnrelatedCode(MyDatabase context)
{
if ( context.Database.CurrentTransaction != null )
{
// Must use the context passed or everything deadlocks :(
localReadOnlyContext = context;
disposeContextLater = false;
}
else
{
// I just want to do this all the time
localReadOnlyContext = _contextFactory.CreateReadOptimized();
disposeContextLater = true;
}
// Do many, many things with my read-optimized context...
// The Dispose() on the class will check for disposeContextLater
}
我想做的是摆脱该事务检查,实际上,如果我能帮助的话,根本不需要传递外部上下文。
我试过的
只是忽略外部事务中发生的事情,并一直使用我生成的上下文。 问题:僵局。
尝试将最外层事务放入_contextFactory
创建的EF上下文中。 问题:EF上下文构造函数不允许您传递现有事务。 Database.CurrentTransaction
也没有设置器。
将整个事务拉出到包裹所有内容的TransactionScope
中。 问题:方法OuterMethod
在上下文中传递,并且我无法控制调用者。
我无法尝试的是:
AlmostUnrelatedCode()
需要到目前为止已写入的数据。 我宁愿不:
AlmostUnrelatedCode
内部使用外部上下文AlmostUnrelatedCode
。 AlmostUnrelatedCode
处理大量数据树,并且上下文很快变得发胖和不快乐。 它很快就用废话污染了上下文,我宁愿在完成后就将其丢弃。 您可以通过将一个连接用于多个上下文来防止死锁。
例
var efConnectionString = ConfigurationManager.ConnectionStrings["SomeEntities"].ConnectionString;
// note EntityConnection, not SqlConnection
using (var conn = new EntityConnection(efConnectionString)) {
// important to prevent escalation
await conn.OpenAsync();
using (var c1 = new SomeEntities(conn, contextOwnsConnection: false)) {
//Use some stored procedures etc.
count1 = await c1.SomeEntity1.CountAsync();
}
using (var c2 = new SomeEntities(conn, contextOwnsConnection: false)) {
//Use some stored procedures etc.
count2 = await c2.SomeEntity21.CountAsync();
}
}
在您的情况下,只需从上下文获取连接并重用它
context.Database.Connection
您AlmostUnrelatedCode
像这样将在AlmostUnrelatedCode
完成的事情分开:
void AlmostUnrelatedCode()
{
var context = _contextFactory.CreateReadOptimized();
AlmostUnrelatedCode(context);
context.Dispose();
}
void AlmostUnrelatedCode(MyDatabase context)
{
// Do many, many things with context...
}
现在,您可以从OuterMethod
调用AlmostUnrelatedCode(with param)
。 也许还有更多的东西需要分离。 考虑S OLID。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.