[英]Linq to entities filtering query using persian calendar
我想使用波斯历月过滤查询。
我原来的查询:
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)',并且该方法无法转换为商店表达式。”}
有人有什么主意吗?
Linq to Entities
仅在其查询上支持规范功能 。 因此,很遗憾,不支持此功能。
如果数据集不是太大,则可以完全检索它(例如,使用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);
有两种不同的方式来读取此问题:
可以通过将查询转换为月份开始和结束之间的范围查询来固定第一部分:
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.Today
和DateTime.Now
始终返回公历日期,因此我假设搜索日期是由用户或通过其他方式输入的波斯日期,并且数据存储在公历中。
在这种情况下,可以使用PersianCalendar方法来计算范围。 DateTime值始终位于公历中,这意味着您无需执行任何操作即可转换为公历:
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这样的库,它知道日历,并且不假定所有本地时间都是公历。
简单(但可能很糟糕*)的答案是:
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,则应该找到一种重构方法。
实体将您的代码转换为sql语言,在这种情况下,它无法将您的函数GetMonth转换为SQL。 快速的解决方法是
var getNews =
(from gn
in db.NewsTables
where gn.Show
select gn).ToList();
但这意味着您将从内存中的数据库获取所有记录,并在选择后应用过滤器。
如果您向我们展示您的功能代码,我们将能够帮助您直接在数据库中进行过滤。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.