【问题标题】:Sort by month in linq and EF在 linq 和 EF 中按月排序
【发布时间】:2015-11-18 19:36:52
【问题描述】:

我有一个 linq 查询,里面是月份名称。我想要按月份(1 月、2 月、3 月、...)排序的结果。

目前我有以下但它给了我和错误:

LINQ to Entities 无法识别方法“System.DateTime” Parse(System.String)' 方法,并且该方法无法翻译 到商店表达式中。

var shockValues = (from s in ctx.Shocks
                               where s.ID == id
                               orderby DateTime.Parse(s.MonthName)
                               select new 
                               {
                                   val = s.MonthName + "=" + s.ShockValue
                               });

【问题讨论】:

  • 为什么不orderby s.MonthName
  • 如果MonthNamestring,您需要执行order by s.MonthName == "Jan" ? 1 : s.MonthName == "Feb" ? 2 : ... 之类的操作。
  • 因为它是一个字符串,不会按月份正确排序
  • 天哪,没有更好的办法:(
  • @user441521 如果您想在数据库中进行排序,则不是。即使在原始 SQL 中,我认为您也必须对 CASE 执行某些操作才能使其正常工作。

标签: c# entity-framework linq


【解决方案1】:

您的选择很少。您可以使用一长串可选运算符将名称映射到数字

order by s.MonthName == "Jan" ? 1 : s.MonthName == "Feb" ? 2 : ...

您可以在数据库中创建一个将名称映射到数值的表

var shockValues = (from s in ctx.Shocks
                   join o in MonthOrder on s.MonthName equals o.MonthName
                   where s.ID == id
                   orderby o.MonthNumber
                   select new 
                   {
                       val = s.MonthName + "=" + s.ShockValue
                   });

或者在内存中排序

var shockValues = (from s in ctx.Shocks
                   where s.ID == id
                   select new
                          {
                              s.MonthName,
                              s.ShockValue
                          })
                  .AsEnumerable()
                  .OrderBy(s => DateTime.ParseExact(s.MonthName, "MMM", CultureInfo.InvariantCulture).Month)
                  .Select(s => new 
                               {
                                   val = s.MonthName + "=" + s.ShockValue
                               });

【讨论】:

  • 内存中的那个很棒。谢谢!
  • @user441521 这只是一个好主意,当你不期望有很多冲击时
  • @esskar 过滤仍在数据库中完成。我想只选择所需的列会更好一些。
【解决方案2】:

这样的东西应该可以工作

var shockValues = ctx.Shocks.Where(s => s.ID == id).Select(x => new {x.MonthName, MonthNum = x.MonthName == "Jan" : 1 ? x.MonthName == "Feb" : 2 ? 0}).OrderBy(s => MonthNum).Select(s => new {val = s.MonthName + "=" + s.ShockValue}     

【讨论】:

  • 月份名称的字母顺序与它们在年内出现的顺序不同。
  • 因为 MonthName 是“Jan”、“Feb”等,因为它是一个字符串,所以无法正确排序。
  • DateTime.Parse 不适用于 EF。这就是 OP 首先遇到的问题。
  • 我明白了。我想我可以在我的选择中执行 if 来获取数字,然后选择它。
  • 这就是我最终要做的。
【解决方案3】:

试试:

orderby Convert.ToDateTime(s.MonthName + " 1, " + DateTime.Now.Year.ToString()).Month

【讨论】:

  • LINQ to Entities 无法识别方法 'System.DateTime ToDateTime(System.String)' 方法,并且该方法无法转换为存储表达式。
  • 您确实使用了“Convert.ToDatetTime”而不是“System.DateTime.ToDatetTime”,对吗?
  • 这是通过 EF 实现的,因此您不能直接使用任何这些功能。
【解决方案4】:

如果你不想在数据库中创建表,你可以这样做

var names = DateTimeFormatInfo.CurrentInfo.MonthNames
            .Take(12).Select(s => new[] {s.Substring(0,3)});

然后根据单独的列表排序。

orderby names.IndexOf(s.MonthName)

【讨论】:

  • @juharr 但是名称列表不是 EF 列表,它是一个普通的字符串数组。
  • EF 仍然需要将其转换为 SQL
  • Juharr 那么可能有正确的方法。将其转换为 AsEnumerable 后,您应该可以使用 Cnvert 和其他 DateTime 函数。
【解决方案5】:

最好和最简单的方法是创建一个存储过程

Create procedure sortevents
   as
 SELECT *
        FROM [SAGMJ].[dbo].[Events]
        ORDER BY CASE 
                 WHEN MONTH([StartAt]) = MONTH(GETDATE())
                    AND YEAR([StartAt])  = YEAR(GETDATE()) THEN 0
                   ELSE 1
                 END, [StartAt];

//接下来调用你的sp

var v = (dc.sortevents()).ToList();

【讨论】:

    猜你喜欢
    • 2016-04-16
    • 2022-12-10
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    • 2015-12-17
    • 2018-06-01
    • 2023-03-08
    • 1970-01-01
    相关资源
    最近更新 更多