我有一个从数据库创建的Entity Framework v5模型。表格Season有一个对应的实体,称为Season。 我需要计算一个Project_Group每年该季节的最小开始日期和最大结束日期。然后,我需要能够在其他LINQ查询中加入那些年度最小/最大季节值。为此,我在数据访问层项目中创建了SeasonLimits类。 (数据库中不存在SeasonLimits表 。)
public partial class SeasonLimits : EntityObject
{
public int Year { get; set; }
public DateTime Min_Start_Date { get; set; }
public int Min_Start_Date_ID { get; set; }
public DateTime Max_End_Date { get; set; }
public int Max_End_Date_ID { get; set; }
public static IQueryable<SeasonLimits> QuerySeasonLimits(MyEntities context, int project_Group_ID)
{
return context
.Season
.Where(s => s.Locations.Project.Project_Group.Any(pg => pg.Project_Group_ID == project_Group_ID))
.GroupBy(x => x.Year)
.Select(sl => new SeasonLimits
{
Year = sl.Key,
Min_Start_Date = sl.Min(d => d.Start_Date),
Min_Start_Date_ID = sl.Min(d => d.Start_Date_ID),
Max_End_Date = sl.Max(d => d.End_Date),
Max_End_Date_ID = sl.Max(d => d.End_Date_ID)
});
}
}
// MVC Project
var seasonHoursByYear =
from d in context.AuxiliaryDateHours
from sl in SeasonLimits.QuerySeasonLimits(context, pg.Project_Group_ID)
where d.Date_ID >= sl.Min_Start_Date_ID
&& d.Date_ID < sl.Max_End_Date_ID
group d by new
{
d.Year
} into grp4
orderby grp4.Key.Year
select new
{
Year = grp4.Key.Year,
HoursInYear = grp4.Count()
};
在我的MVC项目中,每当我尝试在LINQ查询JOIN中使用QuerySeasonLimits方法时,都会收到消息,
“ LINQ to Entities无法识别该方法 'System.Linq.IQueryable`1 [MyDAL.SeasonLimits] QuerySeasonLimits(MyDAL.MyEntities,MyDAL.Project_Group)'方法,和 此方法不能转换为商店表达式。”
是否由于SeasonLimits不是数据库中存在的实体而产生此错误?如果无法以这种方式完成此操作,是否还有另一种方法可以引用该逻辑,以便可以在其他LINQ查询中使用它?
答案 0 :(得分:1)
EF正在尝试将查询转换为SQL,并且由于方法与生成的SQL之间没有直接映射,因此会出现错误。
第一种选择是不使用该方法,而是直接在原始查询中编写该方法的内容(由于目前还没有运行VS,目前不确定是否可以使用该方法)。在这种情况下,您很有可能会遇到性能非常差的非常复杂的SQL。
因此,第二种选择是:不要害怕使用多个查询来获取所需的内容。有时,向数据库发送更简单的查询并继续进行C#代码的修改(聚合,选择等)也很有意义。每当您尝试枚举查询,或者使用(1|subject) + (1|scenario)
,ToList
,ToDictionary
,ToArray
方法之一或正在使用时,查询都会转换为SQL。 ToLookup
,First
,FirstOrDefault
或Single
调用(有关详细信息,请参见LINQ documentation)。
一个可能解决您的查询(但很可能不是最佳解决方案)的示例是使用以下命令启动查询:
SingleOrDefault
,其余所有继续。这一微小变化具有根本影响:
var seasonHoursByYear =
from d in context.AuxiliaryDateHours.ToList()
[...]
,将立即查询数据库,整个数据库
ToList
表将被加载到应用程序中(如果表中的行太多,这将是性能问题)AuxiliaryDateHours
调用)ToList
查询的其余部分:seasonHoursByYear
,分组,...将在内存中发生在这一点上可能还有其他一些不相关的地方。
我还没有真正研究过代码的意图-因为这可能导致进一步的优化-甚至是完全的返工,最终都可以为您带来更多收益...
答案 1 :(得分:0)
我删除了SeasonLimits对象和QuerySeasonLimits方法,并将该方法的内容直接写在原始查询中。
// MVC Project
var seasonLimits =
from s in context.Season
.Where(s => s.Locations.Project.Project_Group.Any(pg => pg.Project_Group_ID == Project_Group_ID))
group s by new
{
s.Year
} into grp
select new
{
grp.Key.Year,
Min_Start_Date = grp.Min(x => x.Start_Date),
Min_Start_Date_ID = grp.Min(x => x.Start_Date_ID),
Max_End_Date = grp.Max(x => x.End_Date),
Max_End_Date_ID = grp.Max(x => x.End_Date_ID)
};
var seasonHoursByYear =
from d in context.AuxiliaryDateHours
from sl in seasonLimits
where d.Date_ID >= sl.Min_Start_Date_ID
&& d.Date_ID < sl.Max_End_Date_ID
group d by new
{
d.Year
} into grp4
orderby grp4.Key.Year
select new
{
Year = grp4.Key.Year,
HoursInYear = grp4.Count()
};