我有一个从数据库创建的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查询中使用它?
EF正在尝试将您的查询转换为SQL,并且由于您的方法与生成的SQL之间没有直接映射,因此您收到错误。
第一个选项是不使用该方法,而是直接在原始查询中写入方法的内容(我现在不确定这是否有效,因为我没有运行VS)。在这种方法可行的情况下,您最有可能最终得到一个性能很差的非常复杂的SQL。
所以这里有第二种选择:不要害怕使用多个查询来获得你需要的东西。有时,将更简单的查询发送到DB并继续在C#代码中进行修改(聚合,选择等)也是有意义的。每次尝试枚举时,或者如果您使用ToList
,ToDictionary
,ToArray
,ToLookup
方法之一,或者如果您使用的是First
,FirstOrDefault
,Single
或SingleOrDefault
调用,查询将被转换为SQL(有关详细信息,请参阅LINQ documentation) )。
一个可能修复查询的示例(但很可能不是最佳解决方案)是使用以下命令启动查询:
var seasonHoursByYear =
from d in context.AuxiliaryDateHours.ToList()
[...]
所有其余的继续。这一微小变化具有根本性影响:
ToList
,将立即查询数据库,并将整个AuxiliaryDateHours
表加载到应用程序中(如果表有太多行,这将是性能问题)ToList
调用)seasonHoursByYear
查询:where
,分组,...将在内存中发生此时还有其他几点可能不相关。
我还没有真正调查过您的代码的意图 - 因为这可能会导致进一步的优化 - 甚至可以为您带来更多收益的全部返工......
我删除了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()
};