【问题标题】:How do i set Savepoints for Linq to SQL and use "NO" ExecuteCommand?如何将 Linq 的保存点设置为 SQL 并使用“NO”ExecuteCommand?
【发布时间】:2010-06-16 12:00:08
【问题描述】:
    TransactionScope TransactionABC = new TransactionScope();
    try
    {
        context.Connection.Open();
        {
            context.ExecuteCommand("insert into test (test) values (1)")
            context.SubmitChanges();
                    context.ExecuteCommand("savepoint test");

            context.ExecuteCommand("insert into test (test) values (2)")
            context.SubmitChanges();

                    context.ExecuteCommand("rollback to test");
            }
    TransactionABC.Complete();
    TransactionABC.Dispose();

            }
   catch (Exception ec)
    {
    MessageBox.Show(" ", ec.Message);
    }
   finally
    {
        context.Connection.Close();
    }

它有效,但仅适用于 ExecuteCommand。我想使用一个函数,因为我看不到保存点中发生了什么!

【问题讨论】:

  • 真的想成为using事务范围。否则,当您遇到异常时,您将交易保持打开状态 - 这很糟糕。它应该是using(var tran = new TransactionScope()) { /* code */ tran.Complete(); } - 然后在成功和失败退出时正确处理它,只有成功调用Complete()

标签: c# linq-to-sql transactions savepoints


【解决方案1】:

我建议不要这样做。这不一定是您想听到的,但尤其是在与TransactionScope 混合时,保存点不是一个好主意。 TransactionScopes 可以嵌套,但是第一次回滚会导致一切,并且提交只发生在最外层的事务中。

在我能想到的大多数情况下,最好先清理数据。您也可以(并且应该)将约束用于安全网,但如果您击中该安全网,请承担大问题并回滚所有内容。


嵌套事务示例:

public void DebitCreditAccount(int accountId, decimal amount, string reference)
{
  using(var tran = new TransactionScope())
  {
    // confirm account exists, and update estimated balance
    var acc = db.Accounts.Single(a => a.Id == accountId);
    acc.BalanceEstimate += amount;
    // add a transaction (this defines the **real** balance)
    db.AccountTransactions.InsertOnSubmit(
         new AccountTransaction {
                 AccountId = accountId, Amount = amount,
                 Code = amount >= 0 ? "C" : "D",
                 Reference = reference });
    db.SubmitChanges();
    tran.Complete();
  }
}
public void Transfer(int fromAccountId, int toAccountId,
           decimal amount, string reference)
{
  using(var tran = new TransactionScope())
  {
    DebitCreditAccount(fromAccountId, -amount, reference);
    DebitCreditAccount(toAccountId, amount, reference);
    tran.Complete();
  }
}

在上面,DebitCreditAccount 是原子的 - 我们将添加帐户交易更新估计余额,或者两者都不更新。如果这是 only 事务,则在此方法结束时提交。

但是,在Transfer 方法中,我们创建了另一个外部事务;我们要么执行bothDebitCreditAccount,要么都不执行。在这里,内部 tran.Complete() (in DebitCreditAccount) 提交 db-transaction,因为存在外部事务。它只是说“我很高兴”。但是,相反,如果 其中一个 内部事务被中止(Dispose() 在没有 Complete() 的情况下调用),那么 外部 事务会立即回滚 em>,并且该事务将拒绝任何额外的工作。 外部事务只有在没有内部事务被中止,并且在外部事务上调用Complete()时才被提交。

【讨论】:

  • 感谢马克的回答!你能给我一个嵌套事务的样本吗?谢谢,尼克
  • @Mark 感谢您的代码。如果两个内部事务都不起作用,我会遇到异常。这个嵌套事务和保存点几乎一样吗?我会说不!我正在寻找与 Savepoint 相同但没有 ExecuteCommand 的代码!谢谢,尼克
  • @nik - 不完全是:回滚内部事务后,您无法完成外部事务。有了保存点,您可以做到这一点。
【解决方案2】:

ExecuteQuery 怎么样?

使用 DataContext.ExecuteQuery,您可以将文本发送到数据库,就像 ExecuteCommand - 但您可以从该文本中获取查询结果。

IEnumerable<int> results = ExecuteQuery<int>(@"
DECLARE @Table TABLE(Id int)
INSERT INTO @Table SELECT {0}
INSERT INTO @Table SELECT {1}
SELECT Id FROM Table", 101, -101);


IEnumerable<Customer> results = ExecuteQuery<Customer>( @"
Rollback transaction
SELECT *
FROM Customer
WHERE ID = {0}", myId);

【讨论】:

  • 你好大卫,你能给我一个想法,你对 ExecuteQuery 有什么看法?坦克,尼克
  • 你好大卫,例如,谢谢,但它“只是”一个回滚!我需要回滚到保存点!还是我明白一些想念的东西?问候,尼克
  • 你可以放任何你想要的sql,就像ExecuteCommand一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多