我有一个具有[Flags]属性的枚举,如下所示:
[Flags]
public enum FlagStatus
{
Value1 = 1
, Value2 = 2
, Value3 = 4
}
我对EF的查询是这样的:
x => x.Status.HasFlag(flagStatus)
现在,如果我设置了flagStatus = FlagStatus.Value1
,则查询工作正常,因为我将值设置为1(。
@__request_Status_0 = 1
WHERE ([o].[StatusId] & @__request_Status_0) = @__request_Status_0)
但是,如果我将其设置为flagStatus = FlagStatus.Value1 | FlagStatus.Value3
,则查询不会返回任何结果,因为翻译后的SQL如下所示:
@__request_Status_0 = 5
WHERE ([o].[StatusId] & @__request_Status_0) = @__request_Status_0)
由于这不是Status字段的有效Id int,因此不会返回任何结果。
所以现在的问题是:.HasFlag不应该由.Net5EF支持吗?还是由于某种原因,按位操作仅限于一个值?如果是这样,为什么要支持比特操作?
我可能错过了什么,但我就是没看到
难道
.HasFlag
不应该由.Net5 EF 支持吗
支持意味着转换为SQL,而不是抛出运行时异常,所以很明显是这样。
由于某种原因是按位操作,仅限于一个值
不,不是。但当与多个值一起使用时,它的含义与您预期的不同。Enum.HasFlags CLR方法的文档说明它返回
true
,如果在标志中设置的一个或多个位字段也在当前实例中设置;否则为false
。
然后在备注中:
HasFlag
方法返回以下布尔表达式的结果。
thisInstance And flag = flag
这正是EF Core正在做的事情。
将其转换为简单单词,它检查标志中的所有位是否存在值(集合的等效All
操作(。而您似乎期望它具有Any
语义。
很快,HasFlag
表示All
。Any
没有专用的方法,所以你应该使用它的直接位操作等价物
(value & flags) != 0
在您的样品中
x => (x.Status & flagStatus) != 0