我有类似以下示例的代码。由于需要通过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
处理大量数据树,并且上下文很快变得发胖和不快乐。它确实会很快用废话污染其上下文,我宁愿在完成后将其丢弃。答案 0 :(得分:1)
您可以通过将一个连接用于多个上下文来防止死锁。
示例
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
答案 1 :(得分:1)
您不能像这样将在AlmostUnrelatedCode
中完成的事情分开:
void AlmostUnrelatedCode()
{
var context = _contextFactory.CreateReadOptimized();
AlmostUnrelatedCode(context);
context.Dispose();
}
void AlmostUnrelatedCode(MyDatabase context)
{
// Do many, many things with context...
}
现在,您可以从AlmostUnrelatedCode(with param)
致电OuterMethod
。也许还有更多的东西需要分离。考虑 S OLID。