2012-05-22 14 views
5

que tiene una aplicación de Windows Forms con .NET 4 y Marco de la entidad para la capa de datos Necesito un método con la transacción, pero haciendo pruebas simples que no podía hacer que funcioneTransacción Ámbito Entidad con

En 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 
    } 
} 

"El proveedor subyacente no se ajustó en Abrir."

¿Alguien tiene alguna idea?

problema resuelto - Mi solución

he resuelto mi problema en hacer algunos cambios. En uno de mis DAL utilizo un Bulk Insert y otros Entity. La transacción problema estaba ocurriendo por el hecho de que el grueso de la transacción (transacción sql) no comprende un alcance de transacción Así que separé la entidad en DAL y usé la transacción sql en su ejecución de forma trivial. ExecuteScalar();

Creo que esa no es la forma más elegante de hacerlo, pero solucionó mi problema de transacción.

Aquí está el código de mi 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

+0

posible duplicado de [El proveedor subyacente falló en Abrir] (http://stackoverflow.com/questions/2475008/the-underlying-provider-failed-on-open) Tiene algunas buenas sugerencias relacionadas con conexiones/transacciones/DTC –

+1

Aquí está usando un antipatrón. Trate el ObjectContext como una unidad de trabajo. – usr

Respuesta

-1

En lugar de emplear TransactionScope, es mejor emplear el patrón UnitOfWork mientras se trabaja con marco de la entidad. Consulte: unit of work pattern

y también;

unit of work and persistance ignorance

+0

El patrón 'UnitOfWork' no es una solución de reemplazo para' TransactionScope' –

+0

@EoinCampbell no es un reemplazo, pero puede emplear el patrón UnitOfWork como un workscope; ¿Puedes aclarar por qué piensas eso? – daryal

+0

Bueno, para empezar, ejemplifica su 'TransactionScope' en su capa de aplicación y no en su DAL, por lo que no está claro si su código es indicativo de la realidad o si ese TS posiblemente abarca otra funcionalidad.En segundo lugar, el patrón 'UOW' solo es útil si ha diseñado su DAL para admitirlo, es decir, Repositorios individuales capaces de tomar una instancia de ObjectContext durante la construcción. Entonces sugieres una revisión bastante drástica en lugar de resolver el problema que ha publicado. Y finalmente, pero probablemente lo más importante ... No puede deshacer un UnitOfWork a menos que esté usando ... Transacciones –

1

De acuerdo con el todopoderoso Google, parece que se abrirá EF/conexiones cercanas con cada llamada a una base de datos. Ya que está haciendo eso, tratará la transacción como usando conexiones múltiples (usando una transacción distribuida). La forma de evitar esto es abrir y cerrar la conexión manualmente al usarla.

Aquí está la información sobre el distributed transactions issue.

Así es como 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(); 
} 
Cuestiones relacionadas