使用不在数据库中的实体对象进行LINQ查询 - 错误:LINQ to Entities无法识别该方法

问题描述 投票:1回答:2

我有一个从数据库创建的Entity Framework v5模型。表Season有一个名为Season的相应实体。 A screenshot of the Entity Framework EDMX showing the Season, Locations, Project, and Project_Group entities我需要为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查询中使用它?

c# entity-framework linq iqueryable
2个回答
1
投票

EF正在尝试将您的查询转换为SQL,并且由于您的方法与生成的SQL之间没有直接映射,因此您收到错误。

第一个选项是不使用该方法,而是直接在原始查询中写入方法的内容(我现在不确定这是否有效,因为我没有运行VS)。在这种方法可行的情况下,您最有可能最终得到一个性能很差的非常复杂的SQL。

所以这里有第二种选择:不要害怕使用多个查询来获得你需要的东西。有时,将更简单的查询发送到DB并继续在C#代码中进行修改(聚合,选择等)也是有意义的。每次尝试枚举时,或者如果您使用ToListToDictionaryToArrayToLookup方法之一,或者如果您使用的是FirstFirstOrDefaultSingleSingleOrDefault调用,查询将被转换为SQL(有关详细信息,请参阅LINQ documentation) )。

一个可能修复查询的示例(但很可能不是最佳解决方案)是使用以下命令启动查询:

var seasonHoursByYear =
    from d in context.AuxiliaryDateHours.ToList()
    [...]

所有其余的继续。这一微小变化具有根本性影响:

  1. 通过调用ToList,将立即查询数据库,并将整个AuxiliaryDateHours表加载到应用程序中(如果表有太多行,这将是性能问题)
  2. 调用QuerySeasonLimits方法时将生成第二个查询(您可以/还应该包含ToList调用)
  3. 其余的seasonHoursByYear查询:where,分组,...将在内存中发生

此时还有其他几点可能不相关。

我还没有真正调查过您的代码的意图 - 因为这可能会导致进一步的优化 - 甚至可以为您带来更多收益的全部返工......


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()
    };
© www.soinside.com 2019 - 2024. All rights reserved.