How to query flags stored as enum in NHibernate
Asked Answered
H

4

3

How to do either a HQL or a Criteria search (the latter is preferred) involving an enum that is used as flags. In other words, I have a persisted enum property that stores some kind of flags. I want to query all the records that have one of these flags set. Using Eq won't work of course because that will only be true, if that is the only flag set.

Solving this using the Criteria API would be the best, but if this is only doable using HQL that is good too.

Hygrometry answered 10/5, 2010 at 19:10 Comment(0)
I
12

Here's how you could do it with the criteria API:

[Flags]
enum Bar{
   A = 0x01,
   B = 0x02,
   C = 0x04
}

var criteria = this.Session.CreateCriteria<Foo>()
            .Add( BitwiseFlags.IsSet( "Bar", Bar.A | Bar.C ) );

using:

public class BitwiseFlags : LogicalExpression
{
    private BitwiseFlags( string propertyName, object value, string op ) :
        base( new SimpleExpression( propertyName, value, op ),
        Expression.Sql( "?", value, NHibernateUtil.Enum( value.GetType() ) ) )
    {
    }

    protected override string Op
    {
        get { return "="; }
    }

    public static BitwiseFlags IsSet(string propertyName, Enum flags)
    {
        return new BitwiseFlags( propertyName, flags, " & " );
    }
}

should generate the following output where clause:

 FROM _TABLE
 WHERE  (this_.Bar & 5 = 5)

which should give you rows that have flags Bar.A and Bar.C set (excluding everything else). You should be able to use it with conjunction and disjunction too.

Ible answered 13/5, 2011 at 8:28 Comment(2)
How can i do this with QueryOver?Pucida
Found the perfect QueryOver solution at github.com/AndreasJilvero/NHibernate.Bitwise. Very grateful to have found that so could add to existing QueryOver queries as opposed to switching them over. Nice and clean implementation.Trilby
L
6

HQL is easy:

var matching = session.CreateQuery(@"
                       from MyEntity
                       where FlagsProperty & :flag = :flag
                       ")
                      .SetParameter("flag", MyEnum.FlagValue)
                      .List<MyEntity>();
Lectureship answered 10/5, 2010 at 22:25 Comment(3)
Is there a way of achieving the same using NHibernate LINQ ? I am trying to do something like this .... from obj in Session.Linq<MyEntity>() where ( obj.FlagsProperty & flag ) == ( flag ) select obj); ...where flag is the parameter but it is throwing exception "System.NullReferenceException : Object reference not set to an instance of an object"Asta
Steve just answered this in the forum, deleting my previous replyLectureship
@Asta Did you find a way to do this with Linq? Thanks.Grigson
H
3

Here is how I solved using Criteria:

Expression.Eq(
  Projections.SqlProjection("({alias}." + propertyname + " & " + 
    ((int)value).ToString() + ") as " + propertyname + "Result",
    new[] { propertyname + "Result" },
    new IType[] { NHibernateUtil.Int32 }
  ), value );
Hygrometry answered 14/5, 2010 at 16:23 Comment(0)
E
-2

You are looking for Expression.Or if you are querying 2 values or Expression.Disjunction if you are querying for more than 2 values:

criteria.Add(
  Expression.Disjunction()
    .Add(Expression.Eq("property", value1))
    .Add(Expression.Eq("property", value2))
    .Add(Expression.Eq("property", value3))
)
Emblematize answered 10/5, 2010 at 21:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.