我正在使用ServiceStack.Ormlite v3.9.71
并在我打开Ormlite SQLite事务时使用以下代码,假设我想在代码中的其他命令中使用此事务:
var connFactory = new OrmLiteConnectionFactory("ConnectionString", SqliteOrmLiteDialectProvider.Instance)
using (IDbConnection db = connFactory.Open()) // using var doesn't make a difference
using (IDbTransaction tran = db.OpenTransaction()) // using var or even db.BeginTransaction() doesn't make a difference
{
// I do lots of boring stuff
...
// Somewhere else in the code
using (var cmd = db.CreateCommand())
{
cmd.Transaction = tran; // get an error
}
}
然而,当我这样做时,我得到了:
A first chance exception of type 'System.InvalidCastException' occurred in System.Data.dll
Additional information: Unable to cast object of type 'ServiceStack.OrmLite.OrmLiteTransaction' to type 'System.Data.Common.DbTransaction'.
Stack Stack:
at System.Data.Common.DbCommand.System.Data.IDbCommand.set_Transaction(IDbTransaction value)
我想这是由于OrmLiteTransaction包装器,我怎样才能进入交易?
答案 0 :(得分:4)
OrmLite提供ToDbTransaction扩展方法。
public static IDbTransaction ToDbTransaction(this IDbTransaction dbTrans)
{
var hasDbTrans = dbTrans as IHasDbTransaction;
return hasDbTrans != null
? hasDbTrans.Transaction
: dbTrans;
}
您可以在代码中使用它。
cmd.Transaction = tran.ToDbTransaction()
希望它能解决你的问题。
答案 1 :(得分:1)
<强>更新强>
OrmLiteConnection将返回一个SqliteCommand,这意味着它无法设置命令的Transaction属性,因为该命令需要一个SqliteTransaction对象。即使您尝试设置IDbCommand.Transaction,也要调用DbCommand.Transaction
setter来检查传递的对象是否为DbTransaction对象
修复是不设置Transaction属性,因为如果已使用db.CreateCommand
db.OpenTransaction
会自行设置它
<强>原始强>
我认为你应该关注@ Mangus&#39;建议并使用var
而不是转换为接口。
检查SqliteOrmLiteDialectProvider的实施情况,它似乎正在使用Mono.Data.Sqlite。 Mono.Data.Sqlite类继承自抽象DbXXX
类,但隐藏基础实现与自己的。
SQLiteCommand.Transaction和SQLiteConnection.CreateCommand具有以下签名:
public new SqliteCommand CreateCommand()
{
...
}
public new SqliteTransaction Transaction
{
...
}
通过强制转换为接口,可以调用DbConnection,DbCommand类中的 base 实现,而不是Mono.Data.Sqlite中的新实现。这意味着OpenTransaction
将返回DbTransaction
派生的对象而不是OrmLiteTransaction对象。
以下代码应该有效:
var connFactory = new OrmLiteConnectionFactory("ConnectionString", SqliteOrmLiteDialectProvider.Instance)
using (var db = connFactory.Open())
using (var tran = db.OpenTransaction()) // or even db.BeginTransaction()
{
// I do lots of boring stuff
...
// Somewhere else in the code
using (var cmd = db.CreateCommand())
{
cmd.Transaction = tran;
}
}
自.NET 2.0以来,ADO.NET提供程序应该派生自DbXXX
抽象类,而不是像IDbConnection
那样实现.NET 1.1接口。
在您的情况下,OrmLite打破了预期的行为,导致与Mono.Data.Sqlite的意外成员隐藏冲突。否则你不会注意到任何事情。