在实体框架查询中使用带标志的枚举
本文关键字:标志 枚举 实体 框架 查询 | 更新日期: 2023-09-27 18:32:26
我有一个如下所示的枚举类型
[Flags]
public enum WeekDays
{
Monday = 1,
Tuesday = 2,
Wednesday = 4,
Thursday = 8,
Friday = 16,
Saturday = 32,
Sunday = 64,
}
WeekDays dw = WeekDays.Friday | WeekDays.Monday | WeekDays.Saturday;
int dwInt = (int)dw;
var list = query.Where(f => f.FromDateTime.DayOfWeek == dwInt "??????????? what can i do there????").ToList();
从实体框架 6.1 开始,可以在请求中使用 HasFlag
扩展方法。
例如:
query.Where(f => f.FromDateTime.DayOfWeek.HasFlag(WeekDays.Friday | WeekDays.Monday)).ToList();
有关功能请求和实现的详细信息,请参阅 https://entityframework.codeplex.com/workitem/1497。
我将猜测您不确定在查询中放入什么以过滤您在源中列出的日期。
鉴于您的源代码片段,我认为可以安全地推断 dwInt 被用作位掩码,并且 DayOfWeek 将有一个位位置"设置"以指示一周中的给定日期。在此基础上,您要做的是使用 dwInt 在"Where is 在星期几上执行逻辑按位 AND "字段,然后检查结果是否大于 0,这意味着在目标字段中设置了所需的星期几"位"之一。我相信这可以解决问题:
var list = query.Where(f => (f.FromDateTime.DayOfWeek & dwInt) >0).ToList()
如果我错误地解释了您的问题,请原谅。
[HasFlags] 属性在某种意义上非常有趣,它不会影响除 .ToString() 和 (AFAIK) Enum.Parse() 操作。因此,对于非字符串操作,枚举类型是否具有 [HasFlags] 属性并不重要。枚举在 EF 中的工作方式是,它们只是强制转换为基础类型,并被视为以下整数类型 int64、int32、int16、byte、sbyte 之一(注意 EDM 不支持无符号整型,因此具有无符号基础类型的枚举将不起作用,并且在数据库中枚举列只是对应于上述类型之一的类型列)。这意味着基本上任何对整数值(EF 支持的类型)有效的操作对枚举值都有效,除非编译器不允许(我认为我不知道任何这样的操作)。这也意味着无论你想把什么放在你的????如果编译,应该可以工作(SQL Server 支持按位运算)
解决方案在这里
public static Dictionary<int, int> map = new Dictionary<int, int>() { { 0, 64 }, { 1, 1 }, { 2, 2 }, { 3, 4 }, { 4, 8 }, { 5, 16 }, { 6, 32 } };
//actually,this comes from the user interface, but we should focus on the database layer
WeekDays[] dw = new WeekDays[] {WeekDays.Saturday,WeekDays.Tuesday,WeekDays.Wednesday };
int[] systemDayOfWeekList = new int[daysOfWeek.Length];
for (int i = 0; i < daysOfWeek.Length; i++)
{
systemDayOfWeekList[i] = map.FirstOrDefault(e => e.Value == (int)daysOfWeek[i]).Key;
}
query = query.Where(f => dayOfWeekList.Contains(((int)SqlFunctions.DatePart("dw", f.FromDateTime))));
我通常会以一种不会在内存中获取结果然后在 c# 中处理它的方式执行此操作,我认为这不是建设性的,而且我的数据库表太大了,无法开始。
我所做的是编写一个查询并将枚举标志作为SQL参数传递,SQL"[ColumnName]&@flag=@flag"与DotNet中使用"property"相同。HasFlag(MyEnum.MyFlagValue)"
public async Task<ICollection<FrequentlyAskedQuestion>> ExecuteAsync(GeoLocation language, ProductGroups productGroup)
{
var p1 = new SqlParameter("p1", (int)language);
var flag = new SqlParameter("flag", (int)productGroup);
using var db= await _contextFactory.CreateDbContextAsync();
return await db.FrequentlyAskedQuestions
.FromSqlRaw("select * from [dbo].[GetFrequentlyAskedQuestions](@p1) where ProductGroup & @flag = @flag", p1,flag)
.OrderByDescending(d=>d.AnswerWasHelpfull)
.AsNoTracking()
.ToArrayAsync();
}
在示例中,我使用了一个 UDF,它以用户的语言或默认语言从表中返回数据。然后,我在需要应用标志的用例中进一步过滤它。
我不知道 EF 为我生成此类查询的可能性,控制和编写查询就可以了,并且对架构的任何更改都会导致单元测试在未传播架构更改时失败。