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

孤者浪人 提交于 2019-12-10 14:41:59

问题


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.


回答1:


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.

P.S: 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;
}



回答2:


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


来源:https://stackoverflow.com/questions/17415046/bitwise-enum-flags-query-using-mongodbs-official-c-sharp-driver

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!