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

当我尝试运行表单的LINQ查询时:

MongoCollection<MyEntity> collection;

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

我得到一个ArgumentException Unsupported where clause: ((Int32)((Int32)entity.Flags & 4) != 0).

这是一个已知的bug /功能吗?

有什么解决方法吗?

从文档看来,MongoDB似乎具有按位更新,但不是按位查询。

为了进行比较,使用ServiceStack作为客户端,相同的查询在Redis之上顺利运行。

我确实发现了这两个链接(link1,link2),它们建议使用JavaScript,但是,这会使服务层的实现非常依赖于数据库技术。


我的解决方案有两个部分。 我为Enum标记制作了一个序列化器,将所有值存储在一个字符串列表中。 我为Linq做了一个扩展方法来“注入”我需要的mongo查询。

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

这样,它的可读性和我不需要将所有对象反序列化到内存中。

PS:GetPropertyName方法只是一种获取属性名称的类型安全方法:

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

从MongoDB v 3.2开始,您可以使用bitsAllSet或bitsAnySet,具体取决于您要搜索的内容。

所以,用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/61945.html

上一篇: Bitwise enum (flags) query using MongoDB's official C# driver

下一篇: Separate queries in MongoDB with ;