我正在尝试使用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();
}
答案 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将不会关闭它。”