为什么使用EF代码的插入在TransactionScope中首先失败?

时间:2011-07-15 18:46:21

标签: c# .net postgresql transactions entity-framework-4.1

我有一种情况,我在一个表(asset_type)中创建一个记录,并通过第二个表(资产)中的外键引用它。在这种情况下,这两个插入都发生在同一个TransactionScope中。

使用原始DbConnection时,插入成功:

conn.ConnectionString = "host=localhost;port=5432;database=test_client_alpha;user id=tcauser;password=tcapw";    

using (var trans = new TransactionScope())
{
  conn.Open();
  conn.EnlistTransaction(Transaction.Current);

  var cmd = conn.CreateCommand();
  cmd.CommandText = "INSERT INTO overview.asset_type ( name ) VALUES( 'Unknown' ) RETURNING id";
  var assetTypeId = (int)cmd.ExecuteScalar();

  cmd.CommandText = string.Format("INSERT INTO overview.asset "
                                  + "(asset_type_id, client_id, is_active, is_gps_active, is_virtual, default_lon, default_lat) "
                                  + "VALUES ({0}, 'mid', TRUE, TRUE, FALSE, 0, 0 ) "
                                  + "RETURNING id ", assetTypeId);
  var assetId = (int)cmd.ExecuteScalar();

  trans.Complete();
}

但是,如果我切换到使用DbContext类,则第二个插入(进入资产)会因外键约束违规而失败,就像第一次插入(进入asset_type)没有发生一样:

conn.ConnectionString = "host=localhost;port=5432;database=test_client_alpha;user id=tcauser;password=tcapw";

using (var trans = new TransactionScope())
{
  using (var context = new TestContext(conn, false))
  {
    var assetTypeId = context.Database
      .SqlQuery<int>("INSERT INTO overview.asset_type ( name ) VALUES( 'Unknown' ) RETURNING id")
      .Single();

    var assetId = context.Database
      .SqlQuery<int>(string.Format("INSERT INTO overview.asset "
                                    + "(asset_type_id, client_id, is_active, is_gps_active, is_virtual, default_lon, default_lat) "
                                    + "VALUES ({0}, 'mid', TRUE, TRUE, FALSE, 0, 0 ) "
                                    + "RETURNING id ", assetTypeId))
      .Single();
    trans.Complete();
  }
}

如果我删除了TransactionScope,则DbContext示例将正常执行。

我尝试过使用IsolationLevel设置(ReadCommitted,ReadUncommitted)但没有成功。

我意识到在这个例子中我不需要TransactionScope。这是涉及与多个数据库交互的大量代码的一部分,需要分布式事务。

我的数据库是PostgreSQL,我正在使用DevArt的dotConnect .NET驱动程序。

有没有人知道为什么DbContext示例不起作用?

1 个答案:

答案 0 :(得分:0)

Managing Connections and Transactions

  

实体框架仅在需要时打开连接,例如执行查询或调用SaveChanges,然后在操作完成时关闭连接。

  • 调用以下任何方法都会打开连接:
  • ObjectContext上的SaveChanges或Refresh。
  • FirstOrDefault,或First on ObjectQuery。
  • 加载EntityCollection。
  • 加载EntityReference。
  • 任何语言集成查询(LINQ)方法或ObjectQuery查询构建器方法,例如Where,OrderBy或Select。

然后它打开另一个连接,事务范围抛出异常。你必须设置Distributed Transaction Coordinator(不能说是PostgreSQL的真实与否)。

如果是真的,那么,在设置完DTC之后,只需打开范围内的conn对象。