2012-05-22 20 views
5

Mam aplikacji formularza systemu Windows z .NET 4 i Entity Framework dla warstwy danych muszę jedną metodę z transakcji, ale dokonywania prostych testów nie mogłem zrobić to pracaZakres Transakcja z Podmiotem

W BLL:

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

W DAL:

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

"Podstawowym dostawcą powiodło się na Open."

Ktoś ma jakieś pomysły?

problem został rozwiązany - moje rozwiązanie

I rozwiązać mój problem robi pewne zmiany. W jednym z moich DAL używam Wstawiania zbiorczego i innych elementów. Wystąpiła problem z transakcją polegającą na tym, że większość transakcji (sql transakcji) nie rozumiała zakresu transakcji Tak więc oddzieliłem jednostkę w DAL i wykorzystałem transakcję sql w jej trywialnym działaniu. ExecuteScalar();

Uważam, że nie jest to najbardziej elegancka metoda, ale rozwiązałem problem z transakcją.

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

dzięki za pomoc

+0

możliwe duplikat [Bazowego operatora nie powiodła się otwarty] (http://stackoverflow.com/questions/2475008/the-underlying-provider-failed-on-open) Ma kilka dobrych sugestii dotyczących połączeń/transakcji/DTC –

+1

Używasz tutaj wzorca antypoślizgowego. Traktuj ObjectContext jako jednostkę pracy. – usr

Odpowiedz

-1

Zamiast zatrudniania TransactionScope, to lepiej zatrudnić UnitOfWork wzór podczas pracy z Entity Framework. proszę odnieść się do: unit of work pattern

a także;

unit of work and persistance ignorance

+0

Wzorzec 'UnitOfWork' nie jest rozwiązaniem zastępczym dla' TransactionScope' –

+0

@EoinCampbell nie jest zamiennikiem, ale można użyć wzorca UnitOfWork, podobnie jak transactioncope; czy możesz wyjaśnić, dlaczego tak uważasz? – daryal

+0

Na początek tworzy "TransactionScope" w swojej warstwie aplikacji, a nie w jego DAL, więc nie jest jasne, czy jego kod wskazuje rzeczywistość, czy też TS może obejmować inną funkcjonalność.Po drugie, wzorzec 'UOW' jest użyteczny tylko wtedy, gdy zaprojektowałeś swój DAL, aby go obsługiwać, tj. Indywidualne repozytoria zdolne do wzięcia instancji ObjectContext podczas budowy. Więc sugerujesz całkiem drastyczny remont zamiast rozwiązania problemu, który opublikował. I na koniec, ale chyba najważniejsze ... Nie możesz wycofać UnitOfWork, chyba że używasz ... Transakcji –

1

Według wszystko potężny Google, wydaje się, że otworzy EF/bliskie powiązania z każdego połączenia z bazą danych. Ponieważ to robi, traktuje transakcję jako korzystanie z wielu połączeń (przy użyciu transakcji rozproszonej). Sposób obejścia tego problemu polega na ręcznym otwieraniu i zamykaniu połączenia podczas korzystania z niego.

Oto informacja o distributed transactions issue.

Oto jak wykonać manually open and close the connection.

Małą próbkę Kod:

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