【问题标题】:How do I use TransactionScope with MySql and Entity Framework? (getting Multiple simultaneous connections...are not currently supported error)如何将 TransactionScope 与 MySql 和实体框架一起使用? (获取多个同时连接...当前不支持错误)
【发布时间】:2012-01-08 01:43:24
【问题描述】:

我有一个新的 .NET 4.0 控制台应用程序,它使用:

  • MySql 6.4.4.0
  • 实体框架 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 也不喜欢 TransactionScope 与 EntityFramework 一起使用。

我希望能够使用事务,尤其是在测试项目中,以便我可以回滚任何更改。

知道如何解决或解决这个问题吗?

完整的错误信息

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>

提前致谢,

【问题讨论】:

  • 您是否有令人信服的理由使用TransactionScope?因为 EF Context 在单个事务中更新数据库。
  • 我想使用 TransactionScope 有几个原因:1)在每个单元测试中,我想在测试完成后恢复数据库(Roy Osherove 的“单元测试艺术”提倡的方法)。我愿意接受更好的建议。 2) 我发现我必须 SaveChanges 以便后续查询能够获取这些更改,而且我在数据访问层中调用了多个自包含操作。我需要业务层将多个独立操作放在一个事务下。同样,我愿意在这里提出建议。
  • @DanC 你找到解决问题的方法了吗?
  • 很遗憾,我找不到可靠的答案,所以我放弃了使用 TransactionScope。相反,从长远来看,也许更好的是,我最终创建了一个 DbContext 接口,这样我就可以在单元测试中使用模拟并且根本不写入数据库。为了真正写入数据库,DbContext 保存更改应充当事务。

标签: .net mysql entity-framework-4 transactions


【解决方案1】:

试试这个,创建上下文后创建事务。

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

【讨论】:

    【解决方案2】:

    请填写范围。

    Complete 方法提交事务。如果抛出异常,

    Complete 不被调用,事务被回滚。

     scope.Complete();
    

    MSDN

    【讨论】:

      猜你喜欢
      • 2016-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-17
      • 2017-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多