Bitwise enum (flags) query using MongoDB's official C# driver

When I try to run a LINQ query of the form:

MongoCollection<MyEntity> collection;

collection.AsQueryable().Where(entity =>
    (entity.Flags & MyFlags.AFlag) != MyFlags.None);

I get an ArgumentException with the message Unsupported where clause: ((Int32)((Int32)entity.Flags & 4) != 0).

Is this a known bug/feature?

Is there any workaround?

From the documentation it seems like MongoDB has a bitwise update, but not a bitwise query.

For comparison, the same query runs smoothly above Redis using ServiceStack as a client.

I did find these two links (link1, link2) which suggest using JavaScript, however, that would make the implementation of the service layer very dependant on the DB technology.


My solution has two parts. I made a serializer for Enum flags that stores all the values in a list of strings. I made an extension method for Linq to "inject" the mongo query i need.

public static IQueryable<TItem> HasFlags<TItem, TProperty>(
    this IQueryable<TItem> items,
    Expression<Func<TItem, TProperty>> itemPropertyExpression,
    params Enum[] enumFlags)
{
    var enumFlagNames = enumFlags.Select(enumFlag => (BsonValue)enumFlag.ToString());
    return items.Where(item => Query.In(ExtendedObject.GetPropertyName(itemPropertyExpression), enumFlagNames).Inject());
}

That way, its both readable and i don't need to deserialize all the objects into memory.

PS: The GetPropertyName method is just a type safe way to get the property name:

public static string GetPropertyName<TClass, TProperty>(
    Expression<Func<TClass, TProperty>> entityPropertyExpression)
{
    return ((MemberExpression)entityPropertyExpression.Body).Member.Name;
}

Starting with MongoDB v 3.2 you can use bitsAllSet or bitsAnySet depending on what are you searching for.

So, with C# MongoDB Driver:

//Check single Flag as OP
collection.Find(Builders<MyEntity>.Filter.BitsAllSet(myEntity => myEntity.Flags, (long) MyFlags.AFlag));

//Check all multiple Flags
collection.Find(Builders<MyEntity>.Filter.BitsAllSet(myEntity => myEntity.Flags, (long) MyFlags.AFlag | MyFlags.BFlag));

//Check any multiple Flag
collection.Find(Builders<MyEntity>.Filter.BitsAnySet(myEntity => myEntity.Flags, (long) MyFlags.AFlag | MyFlags.BFlag));
链接地址: http://www.djcxy.com/p/61946.html

上一篇: Mongodb,concat在一个查询中更新更新

下一篇: 使用MongoDB的官方C#驱动程序进行按位枚举(标志)查询