Home > Blockchain >  Make custom Restriction NHibernate for QueryOver
Make custom Restriction NHibernate for QueryOver

Time:03-12

I'm stuck in a simple problem, I'd like to add a new custom restriction in NHibernate. I want to write a simple QueryOver with a fulltext index, an example with a Projections is here How to use Full Text Search for any property with QueryOver API

But I need a more flexibility so I'd like something like

criteria = criteria.WhereRestrictionOn(() => table.COLUMN_WITHFULLTEXTINDEX).Contains(valueToCheck);

Is it possible? I'm trying in the latest to days surfing over the NHibernate source code but I could't get anything usefull.

Thanks

CodePudding user response:

Since I must manage two different dbs dialect (SQL SERVER and ORACLE) I made the following.

A class that has all the custom criterions, now only one for full text

/// <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);
        }


    }

Then a class who have to manage custom criterion

/// <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 isn't strictly necessary but the ORACLE syntax is

CONTAINS (a, b)>0

So I must to add the ">0".

DbUtil build the syntax by the dialect, e.g. in ORACLE

public SqlString GetFullText(SqlString[] columnNames) {

    var sqlBuilder = new SqlStringBuilder(4 * columnNames.Length);

    sqlBuilder.Add(columnNames[0]);
    sqlBuilder.Add("> 0");

    return sqlBuilder.ToSqlString();
}

Without using FullTextCriterion for ORACLE dialect I could use more simplest solutions that use custom projection instead custom criterion: NHibernate QueryOver Coalesce a property to another property

CodePudding user response:

You can do something like below:

Expression<Func<ProductsEntity, bool>> where = (x => x.MyProperty == "my value"));

...
...

session.Query<ProductsEntity>().Where(where)....

Alternatively, you can build the Junction conditionally like below:

Junction where = Restrictions.Conjunction();
if(string.IsNullOrEmpty(myInputValue) == false)
    where.Add(Restrictions.Eq(Projections.Property<ProductsEntity>(x => x.MyProperty), myInputValue));

  • Related