【问题标题】:Why doesn't AbortTransaction work?为什么 AbortTransaction 不起作用?
【发布时间】:2014-12-25 04:43:15
【问题描述】:

我正在使用 npoco,尝试处理事务,我无法使用 AbortTransaction 方法回滚数据库中的任何内容。

public class ItemRepository
{
  private Func<Database> _db;

  public ItemRepository(Func<Database> db)
  {
        _db = db;
  }

Public void Update(){
    using (_db().Transaction)
    {
        _db().BeginTransaction();
        foreach (var item in itemToUpdate.Items)
        { 
            _db().Insert(item);
            if (SomethingIsNotCorrect())
            {
                _db().AbortTransaction();
            }
        }
    _db().CompleteTransaction();
    }
}}

从测试类调用:

_db = () => new Database(String.Format("DataSource={0};Persist Security Info=False;", DbPath),"System.Data.SqlServerCe.4.0");
_itemRepository = new ItemRepository(() => _db());
_itemRepository.Update();

-------------建议答案后编辑:

var db = _db();
using (db.Transaction)
{
    db.BeginTransaction();  
    foreach (var item in itemToUpdate.Items)
    {
        db.Insert(item);
        db.Transaction.Commit();
        if (GetNutrientConns(itemToUpdate).Count > 2)
        {
             db.AbortTransaction();
        }
    }  
    db.CompleteTransaction();
}

现在我必须使用 db.Transaction.Commit() 在 db 中插入一些东西。然后,当尝试运行 db.AbortTransaction() 时,我收到错误消息:

“此 SqlCeTransaction 已完成;它不再可用。”

【问题讨论】:

  • 什么是_db()?不要说它是返回新数据库连接的方法
  • @Reniuz, private Func _db;在构造函数中设置一次,所以应该是一样的..
  • @daniel_aren 我以前从未使用过这个库,但我强烈怀疑你应该调用一次,将结果存储在字段或变量中,然后反复引用它。
  • 实际上,您能否在此处向我们展示您作为调用图一部分的所有代码,所以我们不会在猜测?请在此处包含构造函数和您所指的任何字段。
  • 这不是您在构造函数中接受的 Database 实例。这是一个返回数据库实例的函数。无论是产生一个新的还是一遍又一遍地返回同一个对我们来说都是不透明的(显然对你来说也是如此,因为你在你的构造函数中接受它)。创建IDatabaseDatabase 或其他类型的字段,并将_db = db() 存储在您的构造函数中。另外,请将您接受的 Func&lt;Database&gt; db 参数重命名为 dbFactory 或其他名称,因为就是这样。

标签: c# .net compact-database npoco


【解决方案1】:

从您的更新中可以清楚地看出问题所在。您正在创建一个工厂函数,该函数实例化并返回一个新的连接/数据上下文,并将其传递给您的存储库构造函数。到目前为止一切顺利。

然后,您将继续在从工厂函数获得的全新 Database 实例上调用每个与事务相关的调用,这没有任何意义。在您的构造函数中,使用您的工厂函数实际获取 Database 实例,并将 that 存储在字段中。根据需要多次使用。

public class ItemRepository
{
    private Database _db;

    public ItemRepository(Func<Database> dbFactory)
    {
        _db = dbFactory();
    }

    ...
}

更新:正如 Mike C 所指出的,为了进一步限制数据上下文的范围和生命周期,最好存储工厂并创建一个位于 @987654325 范围内的 Database 实例@方法,像这样:

public class ItemRepository
{
    private Func<Database> _dbFactory;

    public ItemRepository(Func<Database> dbFactory)
    {
        _dbFactory = dbFactory;
    }

    public void Update() {
        var db = _dbFactory();

        // Now use db wherever you were using _db()
        ...
    }
}

【讨论】:

  • 或者,OP 可以简单地在每个方法的开头调用工厂方法,并在整个调用过程中使用返回的实例。这将有助于确保线程安全,因为没有两个对 Update 的调用可以共享同一个实例。
  • @MikeC 这是一个公平的观点。无论哪种方式,每次调用 Update 方法时,对工厂函数的调用不应超过一次。
  • @Asas,很抱歉,但这无济于事.. 我需要了解 npoco 如何处理事务..
  • @daniel 看起来您从根本上误解了数据库事务是什么。事务允许您以原子方式对一组数据库交互进行分组,并能够通过提交事务或通过回滚恢复事务开始以来的所有内容来将它们全部设置为一成不变。您不能回滚已提交的事务。这毫无意义,与npoco无关
  • @daniel_aren 您可能希望在不提交的情况下“预览”事务的效果,但这与您选择的数据库中的隔离级别有关,同样,与 npoco 或您向我们展示的代码。
【解决方案2】:

最终解决方案更新方法:

var db = _dbFactory();
public void Update() {
try
{
    db.BeginTransaction();
    foreach(item in itemlist)
    {
        db.Insert(item);
    }
    db.CompleteTransaction();
}
catch(Exception)
{
    db.Transaction.Rollback();
}

我不确定异常中是否需要回滚,因为当我使用抛出异常进行测试时,事务消失了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-07
    • 2019-08-06
    • 2016-07-05
    • 2011-08-06
    • 2013-01-18
    相关资源
    最近更新 更多