Linq向实体过滤使用波斯日历查询

时间:2015-02-06 13:05:37

标签: c# sql linq

我想使用波斯语日历过滤我的查询。

我的原始查询:

var getNews =
    from gn
    in db.NewsTables
    where gn.Show
    select gn;

波斯日历对象:

PersianCalendar pc = new PersianCalendar();

并过滤原始查询,如下所示:

getNews = getNews.Where(nm => pc.GetMonth(nm.InsertionDate) == 9 && pc.GetYear(nm.InsertionDate) == pc.GetYear(DateTime.Now));

和例外:

  

base {System.SystemException} = {" LINQ to Entities无法识别   方法' Int32 GetMonth(System.DateTime)'方法和这种方法   无法翻译成商店表达。"}

任何人都有任何想法?

4 个答案:

答案 0 :(得分:1)

Linq to Entities仅支持canonical functions查询。所以这是不幸的是不支持。

如果数据集不是太大,您可以完全检索它(例如,使用ToList()),然后使用Linq to Objects过滤它,只需考虑必须检索整个数据集(如果数据库服务器不是本地的,则传输),这可能会对内存和性能产生影响。

或者,如果数据库记录存储在格里高利日期(如评论中所述),您可以事先进行转换......遵循您的代码:

var gregorianDate = new DateTime(DateTime.Now.Year, 9, 1, new PersianCalendar());
getNews = getNews.Where(nm => nm.InsertionDate.Month == gregorianDate.Month  
                           && nm.InsertionDate.Year == gregorianDate.Year);

答案 1 :(得分:1)

有两种不同的方法可以阅读这个问题:

  1. 您希望在一个月内获得所有记录
  2. 存储的日期与机器的日期不同
  3. 第一部分可以通过将查询转换为月末的开始和结束之间的范围查询来修复:

    var startDate=DateTime.Today.AddDays(1-DateTime.Today.Day);
    var endDate=startDate.AddMonths(1);
    
    var getNews = from gn in db.NewsTables
                  where gn.Show 
                    && gn.InsertionDate >=startDate
                    && gn.InsertionDate <endDate
                  select gn;
    

    DateTime.TodayDateTime.Now总是返回格里高利日期,所以我假设搜索日期是由用户输入的,或者通过其他方式输入为波斯日期,数据存储在公历中。

    在这种情况下,您可以使用PersianCalendar方法计算范围。 DateTime值始终在公历中,这意味着您必须做任何事情才能转换为Gregorian:

    var calendar =  new PersianCalendar();
    var startDate= calendar.AddDays(searchDate,1- calendar.GetDayOfMonth(searchDate));
    var endDate=calendar.AddMonths(startDate,1);
    
    var getNews = from gn in db.NewsTables
                  where gn.Show 
                    && gn.InsertionDate >=startDate
                    && gn.InsertionDate <endDate
                  select gn;
    

    我建议您使用像Jon Skeet的Noda Time这样的图书馆,它知道日历并且没有假设所有当地时间都是格里高利

答案 2 :(得分:-1)

容易(但可能很糟糕)的答案是:

getNews = getNews.ToList();
getNews = getNews.Where(nm => pc.GetMonth(nm.InsertionDate) == 9 && pc.GetYear(nm.InsertionDate) == pc.GetYear(DateTime.Now));

正如Jcl所说,错误的原因是LINQ to Entities只支持有限数量的函数(可以转换为底层提供程序可以支持的表达式)。您的pc.GetMonth功能不是它理解的功能。

通过执行ToList(),您强制查询在服务器上执行并返回结果。现在getNews只是本地内存中的一个集合,任何进一步的LINQ操作都将使用LINQ to Objects完成,它没有上述限制。

*如果在过滤之前数据集很小,这只是一个很好的解决方案,因为getNews查询的整个结果集必须返回并存储在内存中才能过滤。如果它是20行,我不会担心它。如果它是2000,你应该找到一种重构的方法。

答案 3 :(得分:-1)

实体将您的代码转换为sql语言,在这种情况下,它无法将您的函数GetMonth转换为SQL。快速解决方法是

var getNews =
    (from gn
    in db.NewsTables
    where gn.Show
    select gn).ToList();

但这意味着您将从内存中的数据库中获取所有记录,并在选择后应用过滤器。

如果您向我们展示您的功能代码,我们将能够帮助您直接在数据库中进行过滤。