2012-01-08 5 views
12

は、私が使用する新しい.NET 4.0コンソールアプリケーション持っている(...複数の同時接続を取得し、現在エラーがサポートされていません):MySqlとEntity FrameworkでTransactionScopeを使用するにはどうすればよいですか?

  • MySQLを6.4.4.0
  • Entity Frameworkの4.2(コードファースト)
  • Visual Studio 2010

これまでのところこれが機能します。私はデータベースの細かい部分を追加して読むことができます。今

、私は次の例のように、のTransactionScopeを追加します。内部の異なる接続文字列と

複数の同時接続または接続:

public static void TestInsert() 
{ 
    using (TransactionScope scope = new TransactionScope()) 
    { 
     using (var context = new MyDbContext()) 
     { 
      // Create a test user 
      DateTime dt = DateTime.Now; 
      var user1 = new User { UserID = 1, UserName = "test" }; 
      context.Users.Add(user1); <-- exception occurs here 

      context.SaveChanges(); 
     } 
    } 
} 

私はこれを実行すると、私はエラーを取得します同じトランザクションは現在サポートされていません。

は、MySQLのも、最新バージョンがEntityFrameworkでの作業のTransactionScopeを好きではないようです。

私はすべての変更をロールバックできるように、特にテストプロジェクトでは、トランザクションを使用することができるようにしたいです。

どのように私はこれを修正するか、それを回避することができますか?

完全なエラー情報

System.Data.DataException was unhandled 
    Message=An exception occurred while initializing the database. See the InnerException for details. 
    Source=EntityFramework 
    StackTrace: 
    at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action) 
    at System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization() 
    at System.Data.Entity.Internal.LazyInternalContext.<InitializeDatabase>b__4(InternalContext c) 
    at System.Data.Entity.Internal.RetryAction`1.PerformAction(TInput input) 
    at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action`1 action) 
    at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabase() 
    at System.Data.Entity.Internal.InternalContext.Initialize() 
    at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) 
    at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() 
    at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext() 
    at System.Data.Entity.Internal.Linq.InternalSet`1.ActOnSet(Action action, EntityState newState, Object entity, String methodName) 
    at System.Data.Entity.Internal.Linq.InternalSet`1.Add(Object entity) 
    at System.Data.Entity.DbSet`1.Add(TEntity entity) 
InnerException: System.Data.EntityException 
    Message=The underlying provider failed on Open. 
    Source=System.Data.Entity 
    StackTrace: 
     at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure) 
     at System.Data.EntityClient.EntityConnection.Open() 
     at System.Data.Objects.ObjectContext.EnsureConnection() 
     at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) 
     at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() 
     at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source) 
     at System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__1[TResult](IEnumerable`1 sequence) 
     at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot) 
     at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression) 
     at System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression) 
     at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source) 
     at System.Data.Entity.Internal.InternalContext.QueryForModelHash() 
     at System.Data.Entity.Internal.InternalContext.CompatibleWithModel(Boolean throwIfNoMetadata) 
     at System.Data.Entity.Database.CompatibleWithModel(Boolean throwIfNoMetadata) 
     at System.Data.Entity.CreateDatabaseIfNotExists`1.InitializeDatabase(TContext context) 
     at System.Data.Entity.Internal.InternalContext.<>c__DisplayClass5.<PerformDatabaseInitialization>b__3() 
     at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action) 
    InnerException: System.NotSupportedException 
     Message=Multiple simultaneous connections or connections with different connection strings inside the same transaction are not currently supported. 
     Source=MySql.Data 
     StackTrace: 
      at MySql.Data.MySqlClient.MySqlConnection.Open() 
      at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure) 
     InnerException: 

クラスの一部を(複雑な何もありません):

[Table("User")] 
public class User 
{ 
    public User() 
    { 
    } 

    // Primary key 
    [Key] 
    public int UserID { get; set; } 
    public string UserName { get; set; } 
} 


public class MyDbContext : DbContext 
{ 
    public MyDbContext() : base("DbContext") 
    { 
    } 

    public DbSet<User> Users { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     // Tell Code First to ignore PluralizingTableName convention 
     // If you keep this convention then the generated tables will have pluralized names. 
     modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 
    } 
} 

App.configファイル:

<?xml version="1.0"?> 
<configuration> 
    <connectionStrings> 
    <clear/> 
    <add name="DbContext" connectionString="Server=localhost; Database=****; Uid=****; Pwd=****;" providerName="MySql.Data.MySqlClient"/> 
    </connectionStrings> 
    <system.data> 
    <DbProviderFactories> 
     <remove invariant="MySql.Data.MySqlClient"/> 
     <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data"/> 
    </DbProviderFactories> 
    </system.data> 
</configuration> 
事前に210の

おかげで、

ダン

+1

「TransactionScope」を使用する理由はありますか? EFの 'Context'は単一のトランザクションでデータベースを更新するためです。 – Eranga

+0

私はTransactionScopeをいくつかの理由で使用したいと思っています:1)各ユニットテストの中で、テストが完了した後にデータベースを復元したいのです(Roy Osheroveの "The Art of Unit Testing"私はより良い提案にオープンしています。 2)後続のクエリでこれらの変更を取得するために、SaveChangesに加えてデータアクセスレイヤで複数の自己完結型操作を呼び出す必要があることがわかりました。単一のトランザクションの下で複数の独立した操作を行うためにビジネスレイヤが必要です。繰り返しますが、私はここに提案をしています。 –

+0

@DanC問題を解決するために何かを見つけましたか? – ken2k

答えて

1

は親切にスコープを完了します。

The Complete method commits the transaction. If an exception has been thrown,

Complete is not called and the transaction is rolled back.

scope.Complete(); 

MSDNを参照してください。

2

これを試して、コンテキストを作成した後にトランザクションを作成してください。

public static void TestInsert() 
{ 
    using (var context = new MyDbContext()) 
    { 
     using (TransactionScope scope = new TransactionScope()) 
     { 
      // Create a test user 
      DateTime dt = DateTime.Now; 
      var user1 = new User { UserID = 1, UserName = "test" }; 
      context.Users.Add(user1); 

      context.SaveChanges(); 

      scope.Complete(); 
     } 
    } 
}