FreeTextExpression for NHibernate 3.2

I upgraded to the latest NHibernate 3.2 and found my FreeText AbstractCriterion wasn’t working as it previously did. ┬áThis updated version works for me:

[Serializable]
public class FreeTextExpression : AbstractCriterion
{
  private readonly string _propertyName;
  private readonly object _value;
  private readonly IProjection _projection;

  /// <summary>
  /// Initializes a new instance of the <see cref="FreeTextExpression"/> class.
  /// </summary>
  /// <param name="projection">The projection.</param>
  /// <param name="value">The value.</param>
  public FreeTextExpression(IProjection projection, object value)
  {
    _projection = projection;
    _value = value;
  }

  /// <summary>
  /// Initialize a new instance of the <see cref="FreeTextExpression" />
  /// class for a named Property and its value.
  /// </summary>
  /// <param name="propertyName">The name of the Property in the class.</param>
  /// <param name="value">The value for the Property.</param>
  public FreeTextExpression(string propertyName, object value)
  {
    _propertyName = propertyName;
    _value = value;
  }

  public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
  {
    var sqlBuilder = new SqlStringBuilder();
    var columnNames = CriterionUtil.GetColumnNames(_propertyName, _projection, criteriaQuery, criteria, enabledFilters);

    if (columnNames.Length != 1)
    {
      throw new HibernateException("Contains may only be used with single-column properties");
    }

    sqlBuilder.Add("freetext(")
      .Add(columnNames[0])
      .Add(",");

    sqlBuilder.Add(criteriaQuery.NewQueryParameter(GetParameterTypedValue(criteria, criteriaQuery)).Single());
    sqlBuilder.Add(")");

    return sqlBuilder.ToSqlString();
  }

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

  public TypedValue GetParameterTypedValue(ICriteria criteria, ICriteriaQuery criteriaQuery)
  {
    var matchValue = _value.ToString();
    if (_projection != null)
    {
      return CriterionUtil.GetTypedValues(criteriaQuery, criteria, _projection, null, matchValue).Single();
    }
    return new TypedValue(NHibernateUtil.String, _value.ToString(), EntityMode.Poco);
  }

  public override IProjection[] GetProjections()
  {
    if (_projection != null)
    {
      return new [] { _projection };
    }
    return null;
  }

  public override string ToString()
  {
    return " freetext(" + (_projection ?? (object)_propertyName) + "," + _value + ")";
  }
}

2 thoughts on “FreeTextExpression for NHibernate 3.2

  1. I liked your extension but can you post some example on how to use it, I feel like we need some more extension to use this as part of a QueryOver query.

      1. You’ll need to add freetext functions to the sql dialect:
        public class FreeTextDialect:MsSql2008Dialect
        {
          public FreeTextDialect()
          {
            RegisterFunction("freetext", new StandardSQLFunction("freetext", null));
            RegisterFunction("contains", new StandardSQLFunction("contains", null));
          }
        }
      2. You then specify NHibernate to use that dialect in your nhibernate.config file.
      3. Finally, to use freetext search with QueryOver:
        var searchedUsers = Session.QueryOver().Where(new FreeTextExpression("Name", query)).List();

      Hope that helps…

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>