事务范围与实体框架(Entity Framework)

5
我是一名能够翻译文本的助手。
我有一个基于.NET 4和Entity Framework的Windows窗体应用程序。我需要一个带有事务的方法,但是通过简单的测试,我无法使其正常工作。
在BLL中:
public int Insert(List<Estrutura> lista)
{
    using (TransactionScope scope = new TransactionScope())
    {
            id = this._dal.Insert(lista);
    }
}

在DAL中:
public int Insert(List<Estrutura> lista)
{
   using (Entities ctx = new Entities (ConnectionType.Custom))
   {
     ctx.AddToEstrutura(lista);
     ctx.SaveChanges(); //<---exception is thrown here
   }
}

"打开底层提供程序时失败。"

有人有什么想法吗?

问题已解决 - 我的解决方案

我通过一些更改解决了我的问题。 在我的DAL中,我使用了批量插入和其他实体。 事务问题是由于事务sql不了解事务范围而发生的 因此,我将实体分离在DAL中,并在其中运行一些琐碎的sql事务。ExecuteScalar();

我认为这不是最优雅的方法,但解决了我的事务问题。

这是我的DAL代码

   using (SqlConnection sourceConnection = new SqlConnection(Utils.ConnectionString()))
   {
        sourceConnection.Open();
        using (SqlTransaction transaction = sourceConnection.BeginTransaction())
        {
            StringBuilder query = new StringBuilder();
            query.Append("INSERT INTO...");
            SqlCommand command = new SqlCommand(query.ToString(), sourceConnection, transaction);
            using (SqlBulkCopy bulk = new SqlBulkCopy(sourceConnection, SqlBulkCopyOptions.KeepNulls, transaction))
            {                           
                bulk.BulkCopyTimeout = int.MaxValue;
                bulk.DestinationTableName = "TABLE_NAME";
                bulk.WriteToServer(myDataTable);

                StringBuilder updateQuery = new StringBuilder();
                //another simple insert or update can be performed here
                updateQuery.Append("UPDATE... ");
                command.CommandText = updateQuery.ToString();
                command.Parameters.Clear();
                command.Parameters.AddWithValue("@SOME_PARAM", DateTime.Now);
                command.ExecuteNonQuery();
                transaction.Commit();
            }
        }
    }

感谢您的帮助。

可能是[The underlying provider failed on Open]的重复问题(https://dev59.com/VnE95IYBdhLWcg3wDpqg),其中提供了一些与连接/事务/DTC相关的好建议。 - Eoin Campbell
1
你在这里使用了反模式。将ObjectContext视为工作单元来处理。 - usr
2个回答

1
根据全能的Google,EF似乎会在每次调用数据库时打开/关闭连接。由于这样做,它将把事务视为使用多个连接(使用分布式事务)。解决此问题的方法是在使用时手动打开和关闭连接。
这里是有关分布式事务问题的信息。
这是如何手动打开和关闭连接
一个小代码示例:
public int Insert(List<Estrutura> lista)
{
    using (TransactionScope scope = new TransactionScope())
    {
        using (Entities ctx = new Entities (ConnectionType.Custom))
        {
            ctx.Connection.Open()

            id = this._dal.Insert(ctx, lista);
        }
    }
}

public int Insert(Entities ctx, List<Estrutura> lista)
{
     ctx.AddToEstrutura(lista);
     ctx.SaveChanges();
}

-1

“UnitOfWork”模式并不能替代“TransactionScope”。 - Eoin Campbell
@EoinCampbell 这不是一种替代方案,但你可以像使用 transactionscope 一样使用 UnitOfWork 模式;你能否澄清一下你的想法? - daryal
只是需要注意的是,如果在EF中,如果您的工作单元中有多个更改,并且不使用事务,则可能会在发生故障时处于不一致状态。 - Menahem
@Menahem,你能澄清一下吗?据我所知,如果有任何失败,数据库中将不会反映任何更改? - daryal
SaveChanges() 在其内部打开了一个 TransactionScope,因此任何未在其中完成的更改(即,如果您在执行其他更改的包装类中调用它)都不是原子性的。 - Menahem
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接