您可以创建自己的自定义 Oracle 方言来解决此问题,或者您可以等待补丁 NH-3814 被接受。最好等待 NHibernate 接受补丁,但如果你没有时间,你可以这样做。
https://nhibernate.jira.com/browse/NH-3814
此类将覆盖 Oracle8iDialect 中的一个方法,以允许 rownum_ 字段用于跳过和取值。我不得不使用反射来调用 ExtractColumnOrAliasNames,因为这是一个私有方法。
internal class Oracle10gDialectExtended : NHibernate.Dialect.Oracle10gDialect
{
public Oracle10gDialectExtended()
{
}
/// <summary>
/// This is from patch NH-3814
/// https://nhibernate.jira.com/browse/NH-3814
/// https://nhibernate.jira.com/secure/attachment/24661/Oracle8iDialect.cs
/// </summary>
/// <param name="sql"></param>
/// <param name="offset"></param>
/// <param name="limit"></param>
/// <returns></returns>
public override NHibernate.SqlCommand.SqlString GetLimitString(NHibernate.SqlCommand.SqlString sql, NHibernate.SqlCommand.SqlString offset, NHibernate.SqlCommand.SqlString limit)
{
sql = sql.Trim();
bool isForUpdate = false;
if (sql.EndsWithCaseInsensitive(" for update"))
{
sql = sql.Substring(0, sql.Length - 11);
isForUpdate = true;
}
string selectColumns = ExtractColumnOrAliasNames(sql);
var pagingSelect = new SqlStringBuilder(sql.Count + 10);
if (offset != null)
{
pagingSelect.Add("select " + selectColumns + " from ( select row_.*, rownum rownum_ from ( ");
}
else
{
pagingSelect.Add("select " + selectColumns + " from ( ");
}
pagingSelect.Add(sql);
if (offset != null && limit != null)
{
pagingSelect.Add(" ) row_ ) where rownum_ <=").Add(limit).Add(" and rownum_ >").Add(offset);
}
else if (limit != null)
{
pagingSelect.Add(" ) where rownum <=").Add(limit);
}
else
{
// offset is specified, but limit is not.
pagingSelect.Add(" ) row_ ) where rownum_ >").Add(offset);
}
if (isForUpdate)
{
pagingSelect.Add(" for update");
}
return pagingSelect.ToSqlString();
}
private string ExtractColumnOrAliasNames(SqlString select)
{
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
MethodInfo info = typeof(NHibernate.Dialect.Oracle8iDialect).GetMethod("ExtractColumnOrAliasNames", flags, null, new Type[] { typeof(SqlString) }, null);
if (info == null)
{
throw new MissingMethodException("Method ExtractColumnOrAliasNames does not exist on class NHibernate.Dialect.Oracle8iDialect");
}
return info.Invoke(this, new object[] { select }) as string;
}
}