1

我正在尝试使用 linq2SQL 将 CSV 文件的内容插入到数据库表中。

如果任何插入失败,我希望能够回滚事务但是当我尝试使用此代码时,我在 - db.Transaction.Commit()处收到以下错误

System.InvalidOperationException 未处理:此 SqlTransaction 已完成;它不再可用。

有谁知道我做错了什么?

using (DataContext db = new DataContext())
{
    db.Connection.Open();
    db.Transaction = db.Connection.BeginTransaction();

    try
    {
        foreach (string entry in entries)
        {
            XXX xxx = new XXX()
            {
                P1 = "something",
                P2 = "something"
            };

            db.XXXX.InsertOnSubmit(xxx);
            db.SubmitChanges();
        }
    }
    catch (Exception)
    {
        db.Transaction.Rollback();
    }
    finally
    {
        db.Connection.Close();
    }

    db.Transaction.Commit();
}
4

4 回答 4

3

好吧,顺序是错误的——你db.Transaction.Commit()在整个大块之后调用,所以即使发生异常并且你已经调用了它也会被调用db.Transaction.Rollback();

将您的代码更改为:

using (DataContext db = new DataContext())
{
    db.Connection.Open();
    db.Transaction = db.Connection.BeginTransaction();

    try
    {
        foreach (string entry in entries)
        {
            ....
            db.XXXX.InsertOnSubmit(xxx);
            db.SubmitChanges();
        }

        db.Transaction.Commit(); <== CALL HERE !!
    }
    catch (Exception)
    {
        db.Transaction.Rollback();
    }
    finally
    {
        db.Connection.Close();
    }
}

在这种情况下,您的 Commit 在 foreach 之后被调用,但如果您遇到异常并执行回滚,则不会调用它。

马克

于 2009-10-05T09:33:49.760 回答
2

是因为您在回滚后进行了提交吗?

您应该将提交放在 try 块中的最后,以便调用回滚或提交。永远不要两者...

更新:正如彼得在他的回答中提到的,我希望关闭或回滚语句都不是必需的,因为使用块将处理(因此也关闭)连接,并且未提交的事务应该自动回滚。

于 2009-10-05T09:33:09.123 回答
2

基于“使用datacontext”将确保当前事务和连接将被关闭的事实,我将假设以下块应该足够了:

01.    using (DataContext db = new DataContext())
02.    {    
03.        db.Connection.Open();    
04.        db.Transaction = db.Connection.BeginTransaction();    
05.
06.        foreach (string entry in entries)        
07.        {                
08.            XXX xxx = new XXX()                
09.            {                        
10.                P1 = "something",                        
11.                P2 = "something"                
12.            };                
13.            db.XXXX.InsertOnSubmit(xxx);                
14.        }    
15.        db.SubmitChanges();        
16.
17.        db.Transaction.Commit();
18.    }

如果在第 05 行和第 16 行之间发生异常,则事务将永远不会被标记为 Commit,因此一旦事务和连接在第 18 行完成,就会回滚。

注意:这里的行为存在差异,我不确定这是不是有意的:除了回滚事务之外,您的 catch 块会吞下异常,从而隐藏发生错误的事实。

更新:我还将 SubmitChanges 调用移出内部循环。您应该能够首先进行插入,然后为所有更改提交一次更改。

于 2009-10-05T09:48:00.357 回答
2

关于“Peter Lillevold”的回答中发布的代码:我可以看到,如果第 15 行发生错误,例如 db.SubmitChanges(),它不会关闭数据库连接。因此,正确的解决方案是:

enter code here
      using (DataContext db = new DataContext())
        {
            // The dispose method of DbConnection will close any open connection
            // and will rollback any uncommitted transactions
            using (DbConnection dbConnection = db.Connection)
            {
                dbConnection.Open();
                db.Transaction = dbConnection.BeginTransaction();
                foreach (string entry in entries)
                {
                    XXX xxx = new XXX()
                    {
                        P1 = "something",
                        P2 = "something"
                    };
                    db.XXXX.InsertOnSubmit(xxx);
                }
                db.SubmitChanges();
                db.Transaction.Commit();
            }
        } 

PS:更多解释请参考http://msdn.microsoft.com/en-us/library/bb292288.aspx,上面写着“如果你提供一个开放的连接,DataContext不会关闭它。”

于 2010-07-29T16:13:25.260 回答