在 C# 中回滚 linq2sql 插入事务的问题

发布于 2024-08-06 10:54:58 字数 857 浏览 3 评论 0原文

我正在尝试使用 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();
}

i am trying to insert the contents of a CSV file into a database table using linq2SQL.

I want to be able to rollback the transaction if ANY of the inserts fail but when i try with this code i get the following error at - db.Transaction.Commit()

System.InvalidOperationException was unhandled: This SqlTransaction has completed; it is no longer usable.

Does anyone know what i am doing wrong?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

醉生梦死 2024-08-13 10:54:58

好吧,顺序是错误的 - 您在整个大块之后调用 db.Transaction.Commit() ,因此即使发生异常并且您已经调用 db.Transaction.Commit() ,它也会被调用。 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 之后调用,但如果遇到异常并执行回滚,则不会调用它。

马克

Well, the ordering is wrong - you are calling db.Transaction.Commit() after the whole big block, so it'll be called even when an exception occured and you already called db.Transaction.Rollback();

Change your code to:

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

In this case, your Commit is called after the foreach, but it will NOT be called if you run into an exception and do a rollback.

Marc

段念尘 2024-08-13 10:54:58

是因为你在回滚之后才进行提交吗?

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

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

Is it because you do the commit after doing the rollback?

You should place the commit last inside the try block, so either rollback or commit are called. Never both...

UPDATE: As Peter mentions in his answer, I expect that neither the Close or Rollback statements are necessary, as the using block will Dispose (thus also Close) the connection, and a transaction that isn't comitted should automatically be rolled back.

萌面超妹 2024-08-13 10:54:58

基于“使用 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 调用移出内部循环。您应该能够首先进行插入,然后针对所有更改提交一次更改。

Based on the fact that "using datacontext" will ensure that the current transaction and connection will be closed, I will assume that the following block should be sufficient:

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.    }

If an exception occurs between line 05 and 16 the transaction will never be marked with Commit and thus rolled back as soon as the transaction and connetion is finalized at line 18.

Note: there is a difference in behavior here which I'm not sure is intentional or not: in addition to rolling back the transaction, your catch block swallows the exception and thus hides the fact that an error have occured.

Update: I would also move the SubmitChanges call out of the inner loop. You should be able to first do your inserts and then the submit changes once for all changes.

遇到 2024-08-13 10:54:58

关于“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 将不会关闭它。”

With regard to the code posted in "Peter Lillevold"'s answer :
I can see that if an error occurs at line 15 e.g. db.SubmitChanges(), it does not close the database connection. Therefore, the correct solution is :

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: For further explaination, please refer to http://msdn.microsoft.com/en-us/library/bb292288.aspx, which says "If you provide an open connection, the DataContext will not close it. "

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文