Ámbito de transacción con entidad

I have a windows form application with .NET 4 and Entity Framework for data layer I need one method with transaction, but making simple tests I couldn't make it work

In BLL:

public int Insert(List<Estrutura> lista)
{
    using (TransactionScope scope = new TransactionScope())
    {
            id = this._dal.Insert(lista);
    }
}

En DAL:

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

"The underlying provider failed on Open."

¿Alguien tiene alguna idea?

PROBLEM RESOLVED - MY SOLUTION

I solved my problem doing some changes. In one of my DAL I use a Bulk Insert and others Entity. The problem transaction was occurring by the fact that the bulk of the transaction (transaction sql) do not understand a transaction scope So I separated the Entity in DAL and used the sql transaction in its running some trivial. ExecuteScalar ();

I believe that is not the most elegant way to do this, but solved my problem transaction.

Here is the code of my 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();
            }
        }
    }

gracias por la ayuda

preguntado el 22 de mayo de 12 a las 14:05

posible duplicado de El proveedor subyacente falló en la apertura Has some good suggestions relating to connections/transactions/DTC -

You are using an anti-pattern here. Treat the ObjectContext as a unit-of-work. -

2 Respuestas

According to the all-mighty Google, it seems that EF will open/close connections with each call to a database. Since it's doing that, it will treat the transaction as using multiple connections (using a distributed transaction). The way to get around this is to open and close the connection manually when using it.

Here's the information on the distributed transactions issue.

Aquí se explica cómo manually open and close the connection.

Una pequeña muestra de código:

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();
}

contestado el 22 de mayo de 12 a las 21:05

Instead of employing TransactionScope, it is better to employ UnitOfWork pattern while working with entity framework. please refer to: patrón de unidad de trabajo

y también;

unit of work and persistance ignorance

contestado el 22 de mayo de 12 a las 15:05

La UnitOfWork pattern is not a replacement solution for TransactionScope - ein campbell

@EoinCampbell it is not a replacement, but you can employ UnitOfWork pattern like a transactionscope; can you clarify why do you think so? - Darial

Well for starters he instantiates his TransactionScope in his application layer and not in his DAL so it's not clear if his code is indicative of reality or if that TS possibly encompasses other functionality. Secondly, the UOW pattern is only of use if you've designed your DAL to support it i.e. Individual Repositories capable of taking an ObjectContext instance during construction. So your suggesting a pretty drastic overhaul instead of solving the problem he's posted. And finally but probably most important... You can't roll back a UnitOfWork unless your using... Transactions - ein campbell

You may be right there is no direct answer. On the otherhand; UnitOfWork pattern is directly used in transaction management. Whether entity framework or nhibernate; the definition of unitofwork pattern by martin fowler states it is to be used for transaction management. m. fowler states: "maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.". - Darial

Also, you stated that you can not rollback a unitofwork unless using transactions; well it depends since you can not rollback the database changes when you commit transaction scope. The same rule applies for unit of work. In the unit of work scope, you can choose not to apply changes to db. Nhibernate applies UnitOfWork pattern using ITransaction interface, which clearly states it is for transaction management. The other parts of the comments about the not being a direct answer, you are right anyway. - Darial

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.