Ale*_*lex 6 .net oracle nhibernate orm fluent-nhibernate
我试图在NHibernate 3.2和Oracle 11gR2中使用期货.虽然我不确定,但这似乎并不支持.我在NHibernate Jira上发现了这个问题,这使得它看起来像Oracle的未来可能.有谁知道如何让期货与Oracle合作?Oracle不受支持的原因究竟是什么?
根据这里的评论,我尝试使用HQL multiquery.我在执行时遇到异常_nhSession.CreateMultiQuery();这是例外:
The driver NHibernate.Driver.OracleDataClientDriver does not support multiple queries.
Run Code Online (Sandbox Code Playgroud)
我还能尝试什么?我使用了错误的驱动程序吗?
小智 8
我想分享一下NHibernate Future查询如何与Oracle协同工作的方式.您可以将以下两个类EnhancedOracleDataClientDriver和EnhancedOracleResultSetsCommand添加到您的项目中,并将NHibernate配置为使用EnhancedOracleDataClientDriver类作为数据库驱动程序.我很感激这种方法是否适用于其他人的反馈.这是上述类的源代码.
EnhancedOracleDataClientDriver.cs
using NHibernate.Engine;
namespace NHibernate.Driver
{
public class EnhancedOracleDataClientDriver : OracleDataClientDriver
{
public override bool SupportsMultipleQueries
{
get
{
return true;
}
}
public override IResultSetsCommand GetResultSetsCommand(ISessionImplementor session)
{
return new EnhancedOracleResultSetsCommand(session);
}
}
}
Run Code Online (Sandbox Code Playgroud)
EnhancedOracleResultSetsCommand.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using NHibernate.Engine;
using NHibernate.SqlCommand;
using NHibernate.SqlTypes;
using NHibernate.Util;
namespace NHibernate.Driver
{
public class EnhancedOracleResultSetsCommand : BasicResultSetsCommand
{
private const string driverAssemblyName = "Oracle.DataAccess";
private SqlString sqlString = new SqlString();
private int cursorCount = 0;
private readonly PropertyInfo oracleDbType;
private readonly object oracleDbTypeRefCursor;
public EnhancedOracleResultSetsCommand(ISessionImplementor session)
: base(session)
{
System.Type parameterType = ReflectHelper.TypeFromAssembly("Oracle.DataAccess.Client.OracleParameter", driverAssemblyName, false);
oracleDbType = parameterType.GetProperty("OracleDbType");
System.Type oracleDbTypeEnum = ReflectHelper.TypeFromAssembly("Oracle.DataAccess.Client.OracleDbType", driverAssemblyName, false);
oracleDbTypeRefCursor = System.Enum.Parse(oracleDbTypeEnum, "RefCursor");
}
public override void Append(ISqlCommand command)
{
Commands.Add(command);
sqlString = sqlString.Append("\nOPEN :cursor")
.Append(Convert.ToString(cursorCount++))
.Append("\nFOR\n")
.Append(command.Query).Append("\n;\n");
}
public override SqlString Sql
{
get { return sqlString; }
}
public override IDataReader GetReader(int? commandTimeout)
{
var batcher = Session.Batcher;
SqlType[] sqlTypes = Commands.SelectMany(c => c.ParameterTypes).ToArray();
ForEachSqlCommand((sqlLoaderCommand, offset) => sqlLoaderCommand.ResetParametersIndexesForTheCommand(offset));
sqlString = sqlString.Insert(0, "\nBEGIN\n").Append("\nEND;\n");
var command = batcher.PrepareQueryCommand(CommandType.Text, sqlString, sqlTypes);
if (commandTimeout.HasValue) {
command.CommandTimeout = commandTimeout.Value;
}
BindParameters(command);
for (int cursorIndex = 0; cursorIndex < cursorCount; cursorIndex++) {
IDbDataParameter outCursor = command.CreateParameter();
oracleDbType.SetValue(outCursor, oracleDbTypeRefCursor, null);
outCursor.ParameterName = ":cursor" + Convert.ToString(cursorIndex);
outCursor.Direction = ParameterDirection.Output;
command.Parameters.Add(outCursor);
}
return new BatcherDataReaderWrapper(batcher, command);
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
三年前,我发布了"NHibernate多查询/期货与Oracle"问题的答案,以及如何使未来的查询与Oracle协同工作的解决方案.就像将两个派生类EnhancedOracleDataClientDriver和EnhancedOracleResultSetsCommand添加到项目中,并将NHibernate配置为使用EnhancedOracleDataClientDriver类作为数据库驱动程序一样简单.
我最近检查了这个问题https://nhibernate.jira.com/browse/NH-2170,并发现开箱即用的NHibernate仍然不支持Oracle的期货.另外,如果我可以分享有关推导这种"增强型"实施方法的任何来源和/或方法,我在StackOverflow上得到了Ruben的问题.此外,有些人测试了这种"增强"方法,并对SQL Server未来没有注意到性能提升这一事实感到失望.
所以我决定花一些时间重新审视这个问题,试图分析和优化"增强"方法.
以下是我对探查器的调查结果:
因此,在仔细分析构建SQL命令并将其组合成批处理的NHibernate源代码之后,我推出了"增强"方法的第2版.我希望NHibernate核心团队会注意到这一点,并考虑将Oracle的期货添加到我最喜欢的ORM中.
顺便说一句,"增强"方法依赖于Oracle refcursors(批处理中每个查询的一个输出refcursor),并且每个会话都有Oracle限制的最大游标,我们必须注意(Oracle XE上的默认值最多为300个游标) ).
用法.将以下两个类EnhancedOracleManagedDataClientDriver和EnhancedOracleManagedResultSetsCommand添加到项目中,并配置NHibernate以使用EnhancedOracleManagedDataClientDriver类作为数据库驱动程序.
EnhancedOracleManagedDataClientDriver.cs
using System;
using System.Data;
using System.Reflection;
using NHibernate.Engine;
using NHibernate.SqlTypes;
using NHibernate.Util;
namespace NHibernate.Driver
{
public class EnhancedOracleManagedDataClientDriver : OracleManagedDataClientDriver
{
private readonly PropertyInfo _oracleCommandBindByName;
private readonly PropertyInfo _oracleDbType;
private readonly object _oracleDbTypeRefCursor;
public EnhancedOracleManagedDataClientDriver()
{
_oracleCommandBindByName = ReflectHelper.TypeFromAssembly(
"Oracle.ManagedDataAccess.Client.OracleCommand", "Oracle.ManagedDataAccess", true).GetProperty("BindByName");
_oracleDbType = ReflectHelper.TypeFromAssembly(
"Oracle.ManagedDataAccess.Client.OracleParameter", "Oracle.ManagedDataAccess", true).GetProperty("OracleDbType");
var enumType = ReflectHelper.TypeFromAssembly(
"Oracle.ManagedDataAccess.Client.OracleDbType", "Oracle.ManagedDataAccess", true);
_oracleDbTypeRefCursor = Enum.Parse(enumType, "RefCursor");
}
public override bool SupportsMultipleQueries => true;
public override IResultSetsCommand GetResultSetsCommand(ISessionImplementor session)
{
return new EnhancedOracleManagedResultSetsCommand(session);
}
protected override void InitializeParameter(IDbDataParameter dbParam, string name, SqlType sqlType)
{
// this "exotic" parameter type will actually mean output refcursor
if (sqlType.DbType == DbType.VarNumeric)
{
dbParam.ParameterName = FormatNameForParameter(name);
dbParam.Direction = ParameterDirection.Output;
_oracleDbType.SetValue(dbParam, _oracleDbTypeRefCursor, null);
}
else
base.InitializeParameter(dbParam, name, sqlType);
}
protected override void OnBeforePrepare(IDbCommand command)
{
base.OnBeforePrepare(command);
if (command.CommandText.StartsWith("\nBEGIN -- multi query\n"))
{
// for better performance, in multi-queries,
// we switch to parameter binding by position (not by name)
this._oracleCommandBindByName.SetValue(command, false, null);
command.CommandText = command.CommandText.Replace(":p", ":");
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
EnhancedOracleManagedResultSetsCommand.cs
using System.Data;
using System.Linq;
using NHibernate.Engine;
using NHibernate.Impl;
using NHibernate.Loader.Custom;
using NHibernate.Loader.Custom.Sql;
using NHibernate.SqlCommand;
using NHibernate.SqlTypes;
using NHibernate.Type;
namespace NHibernate.Driver
{
public class EnhancedOracleManagedResultSetsCommand : BasicResultSetsCommand
{
private readonly SqlStringBuilder _sqlStringBuilder = new SqlStringBuilder();
private SqlString _sqlString = new SqlString();
private QueryParameters _prefixQueryParameters;
private CustomLoader _prefixLoader;
public EnhancedOracleManagedResultSetsCommand(ISessionImplementor session)
: base(session) {}
public override SqlString Sql => _sqlString;
public override void Append(ISqlCommand command)
{
if (_prefixLoader == null)
{
var prefixQuery = (SqlQueryImpl)((ISession)Session)
// this SQL query fragment will prepend every SELECT query in multiquery/multicriteria
.CreateSQLQuery("\nOPEN :crsr \nFOR\n")
// this "exotic" parameter type will actually mean output refcursor
.SetParameter("crsr", 0, new DecimalType(new SqlType(DbType.VarNumeric)));
_prefixQueryParameters = prefixQuery.GetQueryParameters();
var querySpecification = prefixQuery.GenerateQuerySpecification(_prefixQueryParameters.NamedParameters);
_prefixLoader = new CustomLoader(new SQLCustomQuery(querySpecification.SqlQueryReturns, querySpecification.QueryString,
querySpecification.QuerySpaces, Session.Factory), Session.Factory);
}
var prefixCommand = _prefixLoader.CreateSqlCommand(_prefixQueryParameters, Session);
Commands.Add(prefixCommand);
Commands.Add(command);
_sqlStringBuilder.Add(prefixCommand.Query);
_sqlStringBuilder.Add(command.Query).Add("\n;\n\n");
}
public override IDataReader GetReader(int? commandTimeout)
{
var batcher = Session.Batcher;
var sqlTypes = Commands.SelectMany(c => c.ParameterTypes).ToArray();
ForEachSqlCommand((sqlLoaderCommand, offset) => sqlLoaderCommand.ResetParametersIndexesForTheCommand(offset));
_sqlStringBuilder.Insert(0, "\nBEGIN -- multi query\n").Add("\nEND;\n");
_sqlString = _sqlStringBuilder.ToSqlString();
var command = batcher.PrepareQueryCommand(CommandType.Text, _sqlString, sqlTypes);
if (commandTimeout.HasValue)
command.CommandTimeout = commandTimeout.Value;
BindParameters(command);
return new BatcherDataReaderWrapper(batcher, command);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1969 次 |
| 最近记录: |