LINQ-запрос с использованием объекта сущности, которого нет в базе данных - Ошибка: LINQ to Entities не распознает метод - PullRequest
0 голосов
/ 28 февраля 2019

У меня есть модель 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 всякий раз, когда я пытаюсь использовать метод QuerySeasonLimits в запросе LINQ JOIN, я получаю сообщение,

"LINQ to Entities не распознает метод 'System.Linq.IQueryable`1 [MyDAL.SeasonLimits] QuerySeasonLimits (MyDAL.MyEntities, MyDAL.Project_Group)', и этот метод не может бытьпереведено в выражение хранилища. "

Эта ошибка генерируется, потому что SeasonLimits не является сущностью, существующей в базе данных?Если это невозможно сделать таким образом, есть ли другой способ ссылаться на логику, чтобы ее можно было использовать в других запросах LINQ?

Ответы [ 2 ]

0 голосов
/ 07 марта 2019

Я удалил объект 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()
    };
0 голосов
/ 28 февраля 2019

EF пытается преобразовать ваш запрос в SQL, и поскольку нет прямого сопоставления между вашим методом и сгенерированным SQL, вы получаете ошибку.

Первый вариант - не использовать метод, а вместо этогонапишите содержимое метода непосредственно в исходном запросе (в настоящий момент я не уверен, сработает ли это, поскольку у меня нет работающей VS).В случае, если это сработает, вы, скорее всего, в итоге получите очень сложный SQL с низкой производительностью.

Итак, вот второй вариант: не бойтесь использовать несколько запросов, чтобы получить то, что вынеобходимость.Иногда также имеет смысл отправить более простой запрос в БД и продолжить модификации (агрегация, выбор, ...) в коде C #.Запрос переводится в SQL каждый раз, когда вы пытаетесь перечислить его, или если вы используете один из методов ToList, ToDictionary, ToArray, ToLookup или если вы используете First, FirstOrDefault, Single или SingleOrDefault вызовы (подробности см. В документации LINQ ).

Один из возможных примеров, который может исправить ваш запрос (но, скорее всего, не лучшее решение),чтобы начать свой запрос с:

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

и продолжить со всеми остальными.Это незначительное изменение имеет фундаментальное влияние:

  1. путем вызова ToList БД будет немедленно запрошена, и вся таблица AuxiliaryDateHours будет загружена в приложение (это будет проблемой производительности, если таблицаслишком много строк)
  2. при вызове вашего метода QuerySeasonLimits будет сгенерирован второй запрос (для этого можно / нужно также включить вызов ToList)
  3. остальная часть seasonHoursByYearзапрос: where, группировка, ... произойдет в памяти

Есть несколько других моментов, которые могут быть не связаны в этой точке.

У меня нетизучил цель вашего кода - поскольку это могло привести к дальнейшей оптимизации - даже к полному доработке, которая могла бы принести вам больше прибыли в итоге ...

...