Oracle ManagedDataAccess.EntityFramework数据库.按位置查询绑定参数
本文关键字:查询 绑定 参数 位置 ManagedDataAccess EntityFramework 数据库 Oracle | 更新日期: 2023-09-27 18:16:44
我有以下代码:
var query = Database.SqlQuery<int>(@"
SELECT CASE WHEN EXISTS (
SELECT 1
FROM v$session v, UsersXxxx u
WHERE v.Client_Info LIKE u.UserName || ';%'
AND v.UserName = :schemaName
AND u.SchemaName = :schemaName
AND v.module = 'XXXX.exe'
AND u.UserKey = :userKey)
THEN 1 ELSE 0 END AS LoggedIn FROM DUAL",
new OracleParameter("schemaName", schemaName),
new OracleParameter("userKey", userKey));
return query.First() != 0;
生成"ORA-01008: not all variables bound"。我怀疑变量被绑定的方式出了问题,最终尝试了这个:
var query = Database.SqlQuery<int>(@"
SELECT CASE WHEN EXISTS (
SELECT 1
FROM v$session v, UsersXxxx u
WHERE v.Client_Info LIKE u.UserName || ';%'
AND v.UserName = :schemaName
AND u.SchemaName = :schemaName
AND v.module = 'XXXX.exe'
AND u.UserKey = :userKey)
THEN 1 ELSE 0 END AS LoggedIn FROM DUAL",
new OracleParameter("asdf", schemaName),
new OracleParameter("fdsa", schemaName),
new OracleParameter("userKey", userKey));
return query.First() != 0;
效果很好!我翻了翻文档,发现了一个简介:
" ODP支持绑定标量参数。. NET和实体框架。在实体框架中,支持按名称绑定参数。不支持按位置绑定。"
不知何故,我认为医生在对我撒谎,它试图按位置绑定。我记得很久以前在EF支持之前修复过这个问题,但是我不记得修复的是什么,更不记得如何在EF中应用相同的技术了。
我的解决方案,虽然笨拙,但工作,但不是有一个选项,使它绑定的名字,而不是由位置?如果有,是什么?
问题是Database.SqlQuery
方法使用底层DbConnection
的CreateCommand
方法。在ODP。这将导致OracleCommand
,默认情况下它按位置绑定参数(BindByName = false
)。
这种行为是不可配置的,没有好的地方可以改变它。作为解决方案,我可以建议使用自定义SqlQuery
方法替换,这将使用BindByName = true
创建OracleCommand
,执行ExecuteReader
并使用ObjectContext.Translate
方法进行映射:
public static class EFExtensions
{
public static IEnumerable<T> DbQuery<T>(this DbContext db, string sql, params object[] parameters)
{
if (parameters != null && parameters.Length > 0 && parameters.All(p => p is OracleParameter))
return OracleDbQuery<T>(db, sql, parameters);
return db.Database.SqlQuery<T>(sql, parameters);
}
private static IEnumerable<T> OracleDbQuery<T>(DbContext db, string sql, params object[] parameters)
{
var connection = db.Database.Connection;
var command = connection.CreateCommand();
((OracleCommand)command).BindByName = true;
command.CommandText = sql;
command.Parameters.AddRange(parameters);
connection.Open();
try
{
using (var reader = command.ExecuteReader())
using (var result = ((IObjectContextAdapter)db).ObjectContext.Translate<T>(reader))
{
foreach (var item in result)
yield return item;
}
}
finally
{
connection.Close();
command.Parameters.Clear();
}
}
}
要使用它,只需替换
context.Database.SqlQuery<..>(...)
与
的电话context.DbQuery<..>(...)
在最新版本的托管驱动程序中,您可以添加一个web.config
条目,默认情况下将BindByName设置为true。
<oracle.manageddataaccess.client>
<version number="*">
<settings>
<setting name="BindByName" value="true" />
</settings>
</version>
</oracle.manageddataaccess.client>