C# 为什么我不能将ServiceStack或MLite中的IDbTransaction强制转换为DbTransaction?
我使用的是C# 为什么我不能将ServiceStack或MLite中的IDbTransaction强制转换为DbTransaction?,c#,sqlite,
ormlite-servicestack,C#,Sqlite,
ormlite Servicestack,我使用的是ServiceStack.Ormlite v3.9.71,在打开Ormlite SQLite事务的地方有以下代码,假设我想在代码中其他地方的命令中使用此事务: var connFactory = new OrmLiteConnectionFactory("ConnectionString", SqliteOrmLiteDialectProvider.Instance) using (IDbConnection db = connFactory.Open()) // using var
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'.
和堆栈跟踪:
at System.Data.Common.DbCommand.System.Data.IDbCommand.set_Transaction(IDbTransaction value)
我想这是由于OrmliTransaction包装器造成的,我如何才能到达事务?更新 OrmLiteConnection将返回一个SqliteCommand,这意味着无法设置该命令的事务属性,因为该命令需要一个SqliteTransaction对象。即使您尝试设置IDbCommand.Transaction,您也将调用
DbCommand.Transaction
setter来检查传递的对象是否是DbTransaction对象
修复方法是简单地不设置事务属性,因为如果已使用db.OpenTransaction
打开事务,则db.CreateCommand
会自行设置事务属性
原创
我认为您应该遵循@Mangus的建议,使用var
,而不是强制转换到接口
检查的实现,它似乎在使用Mono.Data.Sqlite。Mono.Data.Sqlite类继承自抽象的DbXXX
类,但用自己的类隐藏基本实现
并有以下签名:
public new SqliteCommand CreateCommand()
{
...
}
public new SqliteTransaction Transaction
{
...
}
通过强制转换到在DbConnection中调用基本实现的接口,DbCommand类代替了Mono.Data.Sqlite中的新实现。这意味着OpenTransaction
将返回一个DbTransaction
派生的对象,而不是ORMLITransaction对象
以下代码应该可以工作:
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
抽象类派生,而不是实现.NET 1.1接口,如IDbConnection
在您的例子中,OrmLite破坏了预期的行为,导致与Mono.Data.Sqlite意外的成员隐藏冲突。否则你不会注意到任何东西。更新 OrmLiteConnection将返回一个SqliteCommand,这意味着无法设置该命令的事务属性,因为该命令需要一个SqliteTransaction对象。即使您尝试设置IDbCommand.Transaction,您也将调用
DbCommand.Transaction
setter来检查传递的对象是否是DbTransaction对象
修复方法是简单地不设置事务属性,因为如果已使用db.OpenTransaction
打开事务,则db.CreateCommand
会自行设置事务属性
原创
我认为您应该遵循@Mangus的建议,使用var
,而不是强制转换到接口
检查的实现,它似乎在使用Mono.Data.Sqlite。Mono.Data.Sqlite类继承自抽象的DbXXX
类,但用自己的类隐藏基本实现
并有以下签名:
public new SqliteCommand CreateCommand()
{
...
}
public new SqliteTransaction Transaction
{
...
}
通过强制转换到在DbConnection中调用基本实现的接口,DbCommand类代替了Mono.Data.Sqlite中的新实现。这意味着OpenTransaction
将返回一个DbTransaction
派生的对象,而不是ORMLITransaction对象
以下代码应该可以工作:
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
抽象类派生,而不是实现.NET 1.1接口,如IDbConnection
在您的例子中,OrmLite破坏了预期的行为,导致与Mono.Data.Sqlite意外的成员隐藏冲突。否则您不会注意到任何东西。OrmLite提供了ToDbTransaction扩展方法
public static IDbTransaction ToDbTransaction(this IDbTransaction dbTrans)
{
var hasDbTrans = dbTrans as IHasDbTransaction;
return hasDbTrans != null
? hasDbTrans.Transaction
: dbTrans;
}
您可以像这样在代码中使用它
cmd.Transaction = tran.ToDbTransaction()
希望它能解决您的问题。OrmLite提供了ToDbTransaction扩展方法
public static IDbTransaction ToDbTransaction(this IDbTransaction dbTrans)
{
var hasDbTrans = dbTrans as IHasDbTransaction;
return hasDbTrans != null
? hasDbTrans.Transaction
: dbTrans;
}
您可以像这样在代码中使用它
cmd.Transaction = tran.ToDbTransaction()
希望它能解决您的问题。什么类型的
db
,您使用的是哪家连接工厂?(即OpenTransaction不是普通IDbConnection接口的一部分)您使用的是哪个版本的OrmLite?tmpTran的类型是什么?它是在哪里创建的?@PanagiotisKanavos,Added/Updated,我的上一次更新弄乱了代码尝试使用使用(IDbConnection db=connFactory.Open())
更改为使用(var db=connFactory.Open())
下一行相同。可能不使用该接口的CreateCommand
版本会重新运行一个可以接受或mliteransaction
@Mangus的命令,但对此不确定。Ormliteransaction实现IDbTransaction,但cmd.Transaction
似乎期望使用DbCommand
,即使其类型是IDbTransaction。在内部,SS使用Mono.Data.Sqlite
。可能是这个驱动程序使用了DbTransaction?什么类型的数据库是db
,您使用的是哪个连接工厂?(即OpenTransaction不是普通IDbConnection接口的一部分)您使用的是哪个版本的OrmLite?tmpTran的类型是什么?它是在哪里创建的?@PanagiotisKanavos,Added/Updated,我的上一次更新弄乱了代码尝试使用使用(IDbConnection db=connFactory.Open())
更改为使用(var db=connFactory.Open())
下一行相同。可能不使用该接口的CreateCommand
版本会重新运行一个可以接受或mliteransaction
@Mangus的命令,但对此不确定。Ormliteransaction实现IDbTransaction,但cmd.Transaction
似乎期望使用DbCommand
,即使其类型是IDbTransaction。在内部,SS使用Mono.Data.Sqlite
。可能是这个驱动程序使用了DbTransaction?不,它不起作用,我原来的帖子中确实有var
关键字,但为了清楚起见,我删除了它,