为 QueryOver 制作自定义限制 NHibernate
Make custom Restriction NHibernate for QueryOver
我遇到了一个简单的问题,我想在 NHibernate 中添加一个新的自定义限制。我想写一个带有全文索引的简单 QueryOver,这里有一个带有投影的示例
但我需要更大的灵活性,所以我想要像
这样的东西
criteria = criteria.WhereRestrictionOn(() => table.COLUMN_WITHFULLTEXTINDEX).Contains(valueToCheck);
可能吗?最近几天我正在尝试浏览 NHibernate 源代码,但我无法获得任何有用的信息。
谢谢
因为我必须管理两种不同的 dbs 方言(SQL SERVER 和 ORACLE),所以我做了以下。
具有所有自定义标准的 class,现在只有一个用于全文
/// <summary>
/// Full custom criterions
/// </summary>
public static class CustomCriterions
{
static CustomCriterions()
{
ExpressionProcessor.RegisterCustomMethodCall(() => FullTextSearch(null, ""), ProcessFullTextSearch);
}
/// <summary>
/// Only a dummy method to force the static constructor <see cref="CustomCriterions"/>
/// </summary>
public static void Register()
{
}
public static bool FullTextSearch(this string objectProperty, string valueToCheck)
{
throw new Exception("Not to be used directly - use inside QueryOver expression");
}
private static ICriterion ProcessFullTextSearch(MethodCallExpression mce)
{
var arg0 = ExpressionProcessor.FindMemberProjection(mce.Arguments[0]).AsProjection();
var arg1 = ExpressionProcessor.FindMemberProjection(mce.Arguments[1]).AsProjection();
var projection = Projections.SqlFunction("contains",
NHibernateUtil.Boolean,
arg0,
arg1);
return new FullTextCriterion(projection);
}
}
然后 class 必须管理自定义标准
/// <summary>
/// Custom criterion to have a full text search
/// </summary>
public class FullTextCriterion : AbstractCriterion
{
private readonly IProjection _projection;
public FullTextCriterion(IProjection projection)
{
_projection = projection;
}
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
var typedValues = new List<TypedValue>();
if (_projection != null)
{
typedValues.AddRange(_projection.GetTypedValues(criteria, criteriaQuery));
}
typedValues.Add(GetParameterTypedValue(criteria, criteriaQuery));
return typedValues.ToArray();
}
private TypedValue GetParameterTypedValue(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return CriterionUtil.GetTypedValues(criteriaQuery, criteria, _projection, null).Single();
}
public override IProjection[] GetProjections()
{
return new[] { _projection };
}
public override string ToString()
{
return _projection.ToString();
}
public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
var columnNames = CriterionUtil.GetColumnNamesForSimpleExpression(
null, _projection, criteriaQuery, criteria, this, string.Empty);
return DbUtil.GetFullText(columnNames);
}
}
FullTextCriterion 不是绝对必要的,但 ORACLE 语法是
包含 (a, b)>0
所以我必须添加“>0”。
DbUtil 通过方言构建语法,例如在甲骨文中
public SqlString GetFullText(SqlString[] columnNames)
{
var sqlBuilder = new SqlStringBuilder(4 * columnNames.Length);
sqlBuilder.Add(columnNames[0]);
sqlBuilder.Add("> 0");
return sqlBuilder.ToSqlString();
}
如果不为 ORACLE 方言使用 FullTextCriterion,我可以使用更简单的解决方案,这些解决方案使用自定义投影而不是自定义标准:
此外,另一种最简单的解决方案是按照此处http://www.andrewwhitaker.com/blog/2014/08/15/queryover-series-part-7-using-sql-functions/所述调用模板,并直接在 ProcessFullTextSearch 方法中调用它。在这个另一个解决方案中,它只能写一个虚拟的 ProjectionAsCriterion class ,它只得到
public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
var columnNames = CriterionUtil.GetColumnNamesForSimpleExpression(
null, _projection, criteriaQuery, criteria, this, string.Empty);
return columnNames[0];
}
模板可以写成方言class如
RegisterFunction("fulltextsearch", new SQLFunctionTemplate(NHibernateUtil.Boolean, "contains(?1, ?2) > 0"));
我遇到了一个简单的问题,我想在 NHibernate 中添加一个新的自定义限制。我想写一个带有全文索引的简单 QueryOver,这里有一个带有投影的示例
但我需要更大的灵活性,所以我想要像
这样的东西criteria = criteria.WhereRestrictionOn(() => table.COLUMN_WITHFULLTEXTINDEX).Contains(valueToCheck);
可能吗?最近几天我正在尝试浏览 NHibernate 源代码,但我无法获得任何有用的信息。
谢谢
因为我必须管理两种不同的 dbs 方言(SQL SERVER 和 ORACLE),所以我做了以下。
具有所有自定义标准的 class,现在只有一个用于全文
/// <summary>
/// Full custom criterions
/// </summary>
public static class CustomCriterions
{
static CustomCriterions()
{
ExpressionProcessor.RegisterCustomMethodCall(() => FullTextSearch(null, ""), ProcessFullTextSearch);
}
/// <summary>
/// Only a dummy method to force the static constructor <see cref="CustomCriterions"/>
/// </summary>
public static void Register()
{
}
public static bool FullTextSearch(this string objectProperty, string valueToCheck)
{
throw new Exception("Not to be used directly - use inside QueryOver expression");
}
private static ICriterion ProcessFullTextSearch(MethodCallExpression mce)
{
var arg0 = ExpressionProcessor.FindMemberProjection(mce.Arguments[0]).AsProjection();
var arg1 = ExpressionProcessor.FindMemberProjection(mce.Arguments[1]).AsProjection();
var projection = Projections.SqlFunction("contains",
NHibernateUtil.Boolean,
arg0,
arg1);
return new FullTextCriterion(projection);
}
}
然后 class 必须管理自定义标准
/// <summary>
/// Custom criterion to have a full text search
/// </summary>
public class FullTextCriterion : AbstractCriterion
{
private readonly IProjection _projection;
public FullTextCriterion(IProjection projection)
{
_projection = projection;
}
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
var typedValues = new List<TypedValue>();
if (_projection != null)
{
typedValues.AddRange(_projection.GetTypedValues(criteria, criteriaQuery));
}
typedValues.Add(GetParameterTypedValue(criteria, criteriaQuery));
return typedValues.ToArray();
}
private TypedValue GetParameterTypedValue(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return CriterionUtil.GetTypedValues(criteriaQuery, criteria, _projection, null).Single();
}
public override IProjection[] GetProjections()
{
return new[] { _projection };
}
public override string ToString()
{
return _projection.ToString();
}
public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
var columnNames = CriterionUtil.GetColumnNamesForSimpleExpression(
null, _projection, criteriaQuery, criteria, this, string.Empty);
return DbUtil.GetFullText(columnNames);
}
}
FullTextCriterion 不是绝对必要的,但 ORACLE 语法是
包含 (a, b)>0
所以我必须添加“>0”。
DbUtil 通过方言构建语法,例如在甲骨文中
public SqlString GetFullText(SqlString[] columnNames) {
var sqlBuilder = new SqlStringBuilder(4 * columnNames.Length);
sqlBuilder.Add(columnNames[0]);
sqlBuilder.Add("> 0");
return sqlBuilder.ToSqlString();
}
如果不为 ORACLE 方言使用 FullTextCriterion,我可以使用更简单的解决方案,这些解决方案使用自定义投影而不是自定义标准:
此外,另一种最简单的解决方案是按照此处http://www.andrewwhitaker.com/blog/2014/08/15/queryover-series-part-7-using-sql-functions/所述调用模板,并直接在 ProcessFullTextSearch 方法中调用它。在这个另一个解决方案中,它只能写一个虚拟的 ProjectionAsCriterion class ,它只得到
public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
var columnNames = CriterionUtil.GetColumnNamesForSimpleExpression(
null, _projection, criteriaQuery, criteria, this, string.Empty);
return columnNames[0];
}
模板可以写成方言class如
RegisterFunction("fulltextsearch", new SQLFunctionTemplate(NHibernateUtil.Boolean, "contains(?1, ?2) > 0"));