Rus*_*ght 2 .net c# entity-framework transactions
我遇到了导致我的应用程序出去吃饭的问题.我已经将这种情况隔离开来,涉及父实体的一个简单的更新(对键或索引没有影响),它包含在TransactionScope中,SaveChanges()在之后的上下文中运行.不久之后,与更新的父项相关的子实体被插入到一个新的上下文实例中,该实例被包装在内部TransactionScope中.为子进程运行SaveChanges()时,线程将一直阻塞,直到达到SqlCommand.CommandTimeout并回滚事务.下面是代码和模型.
我在这里展示了用于演示的体系结构,但外部事务由一个处理队列并旋转各种类的作业管理器启动.内部事务逻辑实际上位于一个帮助程序类中,其目的是允许作业类进行更新,如果外部事务被撤消,则不会回滚.
我的拙劣猜测是内部SaveChanges()无法完成,因为外部SaveChanges()和事务尚未完成.这会使父级处于不确定状态,因此无法验证约束.虽然,我对System.Transaction和EF的理解仍然相当绿色.
希望是避免建筑改变,或至少保持超级小.我们目前正在运行.NET4和EF5.建议?非常感谢提前.
编辑: 修复了标题歧义并添加了SQL诊断输出的屏幕截图.
码
using System;
using System.Linq;
using System.Transactions;
using SSI.Server.DataContext;
using SSI.Server.DataModel;
namespace MyBox
{
class MyBox
{
static void Main(string[] args)
{
Console.WriteLine("Firing up context...");
var context = new SsiContext();
if (!context.parent.Any(p => p.Name == "Mom"))
{
context.parent.Add(new parent()
{
Name = "Mom"
});
context.SaveChanges();
}
var tranOpts = new TransactionOptions();
tranOpts.IsolationLevel = IsolationLevel.ReadCommitted;
tranOpts.Timeout = TimeSpan.FromSeconds(300);
using (var outerTran = new TransactionScope(TransactionScopeOption.Required, tranOpts))
{
var mom = context.parent.FirstOrDefault(p => p.Name == "Mom");
if(mom == null) { throw new InvalidOperationException("Where's momma!?"); }
Console.WriteLine("Setting parent number and saving in first transaction...");
mom.Number = 1980;
context.SaveChanges();
using (var innerTran = new TransactionScope(TransactionScopeOption.RequiresNew, tranOpts))
{
Console.WriteLine("Second transaction create. Spinning up new context...");
var innerContext = new SsiContext();
Console.WriteLine("Creating new child, linking to parent, saving, and closing inner transaction...");
innerContext.child.Add(new child() { ParentId = mom.ParentId });
// Execution hangs here
innerContext.SaveChanges();
innerTran.Complete();
}
Console.WriteLine("Completing outer transaction...");
outerTran.Complete();
}
Console.WriteLine("Done");
Console.ReadKey();
}
}
}
Run Code Online (Sandbox Code Playgroud)
父模型
public class parent
{
public string ParentId { get; set; }
public string Name { get; set; }
public int Number { get; set; }
protected virtual ICollection<child> children { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
父配置
public class parentMap : EntityTypeConfiguration<parent>
{
public parentMap()
{
this.HasKey(t => t.ParentId);
this.Property(t => t.ParentId).IsRequired().HasMaxLength(40);
this.Property(t => t.Name).HasMaxLength(20);
this.Property(t => t.Number);
}
Run Code Online (Sandbox Code Playgroud)
}
儿童模特
public class child
{
public string ChildId { get; set; }
public string ParentId { get; set; }
public string Name { get; set; }
public int Number { get; set; }
protected virtual parent parent { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
儿童配置
public class childMap : EntityTypeConfiguration<child>
{
public childMap()
{
this.HasKey(t => t.ChildId);
this.Property(t => t.ChildId).IsRequired().HasMaxLength(40);
this.Property(t => t.ParentId).IsRequired().HasMaxLength(40);
this.Property(t => t.Name).HasMaxLength(20);
this.Property(t => t.Nubmer);
}
}
Run Code Online (Sandbox Code Playgroud)
SQL SPID信息

您遇到了僵局.
您有两个不同的数据库事务(由于该RequiresNew选项,内部事务范围创建了一个新事务.您的第一个事务是锁定第二个事务所需的某些数据库资源.第二个事务被数据库阻止,并且因为第一个事务不能完成直到第二个完成,锁永远不会释放.
SQL服务器可以检测到死锁,但在这种情况下它不能 - 它无法知道第一个事务在完成第二个事务之前不会完成.
| 归档时间: |
|
| 查看次数: |
2589 次 |
| 最近记录: |