Oracle ManagedDataAccess.EntityFramework Database.SqlQuery绑定参数的位置?

我有以下代码:

var query = Database.SqlQuery(@" 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:并非所有变量都受到约束”。 我怀疑变量被绑定的方式出现了问题,最后尝试了这个:

  var query = Database.SqlQuery(@" 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和Entity Framework支持绑定标量参数。在Entity Framework中,支持按名称进行参数绑定。不支持按位置绑定。”

不知怎的,我认为文档对我说谎,并且它试图按位置绑定。 我记得很久以前在EF支持之前解决这个问题,但我不记得修复是什么,更不用说如何在EF中应用相同的技术。

我的解决方法,虽然kludgy,工作但是没有一个选项,使其通过名称而不是位置绑定? 如果是这样,它是什么?

问题是Database.SqlQuery方法使用底层DbConnectionCreateCommand方法。 在ODP.NET中,这会导致OracleCommand ,它默认按位置绑定参数( BindByName = false )。

这种行为是不可配置的,没有改变它的好地方。 作为一种解决方法,我可以建议使用自定义SqlQuery方法替换,它将使用BindByName = true创建OracleCommand ,执行ExecuteReader并使用ObjectContext.Translate方法进行映射:

 public static class EFExtensions { public static IEnumerable DbQuery(this DbContext db, string sql, params object[] parameters) { if (parameters != null && parameters.Length > 0 && parameters.All(p => p is OracleParameter)) return OracleDbQuery(db, sql, parameters); return db.Database.SqlQuery(sql, parameters); } private static IEnumerable OracleDbQuery(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(reader)) { foreach (var item in result) yield return item; } } finally { connection.Close(); command.Parameters.Clear(); } } } 

为了使用它,只需更换

 context.Database.SqlQuery<..>(...) 

打电话给

 context.DbQuery<..>(...) 

在最新版本的托管驱动程序中,您可以添加一个web.config条目,默认情况下将BindByName设置为true。