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

时间:2009-10-05 09:12:43

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

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

如果插入的 ANY 失败,我希望能够回滚事务但是当我尝试使用此代码时,我会收到以下错误 - 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 个答案:

答案 0 :(得分: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之后被调用,但是如果您遇到异常并进行回滚,它将 NOT 被调用。

马克

答案 1 :(得分:2)

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

您应该将提交最后放在try块中,以便调用rollback或commit。从来没有......

更新:正如Peter在他的回答中提到的那样,我希望Close或Rollback语句都不是必需的,因为using块将Dispose(因此也是Close)连接,并且一个未被调用的事务应该自动滚动回来。

答案 2 :(得分: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调用移出内部循环。您应该能够先进行插入操作,然后对所有更改进行一次提交更改。

答案 3 :(得分: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将不会关闭它。”