Dan*_*rod 5 c# linq bitwise-operators mongodb mongodb-.net-driver
当我尝试运行以下形式的LINQ查询时:
MongoCollection<MyEntity> collection;
collection.AsQueryable().Where(entity =>
(entity.Flags & MyFlags.AFlag) != MyFlags.None);
Run Code Online (Sandbox Code Playgroud)
我收到一条ArgumentException消息Unsupported where clause: ((Int32)((Int32)entity.Flags & 4) != 0).
这是已知的错误/功能吗?
有什么解决方法吗?
从文档看来,MongoDB似乎有按位更新,但没有按位查询。
为了进行比较,使用ServiceStack作为客户端,同一查询在Redis上运行平稳。
我确实找到了这两个建议使用JavaScript的链接(link1,link2),但这将使服务层的实现非常依赖于DB技术。
从MongoDB v 3.2开始,您可以根据要搜索的内容使用bitsAllSet或bitsAnySet。
因此,使用C#MongoDB驱动程序:
//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));
Run Code Online (Sandbox Code Playgroud)
我的解决方案有两个部分。我为枚举标志创建了一个序列化器,它将所有值存储在字符串列表中。我为 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());
}
Run Code Online (Sandbox Code Playgroud)
这样,它既可读,又不需要将所有对象反序列化到内存中。
PS:GetPropertyName 方法只是获取属性名称的类型安全方法:
public static string GetPropertyName<TClass, TProperty>(
Expression<Func<TClass, TProperty>> entityPropertyExpression)
{
return ((MemberExpression)entityPropertyExpression.Body).Member.Name;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1871 次 |
| 最近记录: |