【问题标题】:EntityFramework in test initialization error: CREATE DATABASE statement not allowed within multi-statement transaction测试初始化​​错误中的 EntityFramework:CREATE DATABASE 语句不允许在多语句事务中
【发布时间】:2023-03-17 11:55:01
【问题描述】:

我正在尝试构建一个快速测试,每次运行时都会删除并重新创建数据库。我有以下内容:

[TestClass]
public class PocoTest
{
    private TransactionScope _transactionScope;
    private ProjectDataSource _dataSource; 
    private Repository _repository = new Repository();
    private const string _cstring = "Data Source=.;Initial Catalog=test_db;Trusted_Connection=True";

    [TestInitialize]
    public virtual void TestInitialize()
    {
        _dataSource = new ProjectDataSource(_cstring);
        _dataSource.Database.Delete();
        _dataSource.Database.CreateIfNotExists();
        _transactionScope = new TransactionScope();
    }
    [TestMethod]
    public void TestBasicOperations()
    {                
        var item = _repository.AddItem(new Item(){Details = "Test Item"});
        //  AddItem makes a call through the data context to add a set and then calls datacontext.SaveChanges()
    }


    [TestCleanup]
    public void TestCleanup()
    {
        // rollback
        if (_transactionScope != null)
        {
            _transactionScope.Dispose();
        }
    }

但是,当我运行测试时,我收到以下错误:

结果消息:测试方法 Project.Repository.UnitTests.PocoTest.TestBasicOperations 抛出 异常:System.Data.SqlClient.SqlException:创建数据库 多语句事务中不允许语句。

ProjectDataSource 在这里:

public class ProjectDataSource : DbContext, IProjectDataSource
{

    public ProjectDataSource() : base("DefaultConnection")
    {

    }

    public ProjectDataSource(string connectionString) : base(connectionString)
    {

    }

    public DbSet<Set> Sets { get; set; }
}

存储库:

public class Repository : IRepository
{
    private readonly ProjectDataSource _db = new ProjectDataSource();
    public Item AddItem(Item item)
        {
            _db.Items.Add(item);
            _db.SaveChanges();
            return item;
        }
}

为什么会这样?

另外 - 如果有任何区别 - 如果我在 TestMethod 中注释掉 AddItem 行,则不会发生错误。

【问题讨论】:

    标签: c# entity-framework


    【解决方案1】:

    你也可以使用db.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sqlCommand);

    详情请见https://stackoverflow.com/a/24344654/375114

    【讨论】:

      【解决方案2】:

      请注意,此错误是有意发生的,每当在活动事务中向 Microsoft SQL Server 发出不可交易命令时就会发生此错误。

      因此,解决方案是允许 Database.CreateIfNotExists() 在任何事务范围之外命中数据库。请记住,SQL Profiler 是您的朋友。

      大致可以得到updated list of commands that are not allowed to run whithin transactions

      注意:如果有人想知道我为什么要提供基于 Sybase 产品的列表,请记住 Microsoft SQL Server 与 Sybase 引擎共享其大部分基本基因。进一步阅读请参考https://en.wikipedia.org/wiki/Microsoft_SQL_Server

      【讨论】:

      • 此答案针对问题的标题,而不是问题的主体。是的,该问题的标题具有误导性,并导致这是您回答的问题的热门 Google 热门问题,但这个问题不是那个问题 x.x。哇
      【解决方案3】:

      如果其他人遇到这个问题:

      在我的 Repository 类中,我对通常标记为“dbContext”的内容有另一个定义 - ProjectDataSource。这意味着一个上下文是在我的测试类中创建的,而另一个上下文是在我的 Repository 对象中创建的。将连接字符串发送到我的 repo 类解决了问题:

      在存储库中:

      public class Repository : IRepository
          {
              private readonly ProjectDataSource _db;
      
              public Repository(string connectionString)
              {
                  _db = new ProjectDataSource(connectionString);   
              }
      
              public Repository()
              {
                  _db = new ProjectDataSource();   
              }
      

      根据我的测试:

      private TransactionScope _transactionScope;
              private Repository _repository;
              private ProjectDataSource _dataSource; 
              private const string _connectionString = "Data Source=.;Initial Catalog=test_db;Trusted_Connection=True";
      
              [TestInitialize]
              public virtual void TestInitialize()
              {
                  _repository = new Repository(_connectionString);
                  _dataSource = new ProjectDataSource(_connectionString);
                  _dataSource.Database.Delete();
                  _dataSource.Database.CreateIfNotExists();
                  _transactionScope = new TransactionScope();
              }
      

      【讨论】:

      • 我不完全明白为什么会出现这个问题。您是说创建 2 个等效的 dbcontext 实例会导致问题。这意味着应用程序中只能存在一个特定db的dbcontext?
      • Eran Otzap,我知道这有点晚了,但是今天遇到了这个问题,我认为发布一个解释根本原因的答案会很有帮助。希望对您有所帮助。
      【解决方案4】:

      您不能围绕某些 SQL 命令使用隐式提交。 创建和删除数据库就是一个例子 SQL 服务器将执行 AUTOCommit

      请参阅 MS SQL 帮助中的备注部分。 http://msdn.microsoft.com/en-us/library/ms176061.aspx

      还有关于 Auto Commit 的更多信息... http://msdn.microsoft.com/en-us/library/ms187878%28v=sql.105%29

      【讨论】:

        【解决方案5】:

        试试这个代码

        使用 (TransactionScope ts = new TransactionScope(TransactionScopeOption.Suppress))

        {
        var sqlCommand = String.Format("创建数据库 [{0}]", "TempBackupDB"); _context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sqlCommand);

        ts.Complete();

        }

        【讨论】:

        • 只创建一个空数据库。然后呢?
        【解决方案6】:

        您需要在包管理器控制台上运行 Update-Database 命令。

        【讨论】:

        • 你将如何在单元测试方法中做到这一点?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-28
        • 1970-01-01
        相关资源
        最近更新 更多