Более простой способ запуска запросов Entity Framework Core в LinqPad со встроенным драйвером Linq to SQL?

Примечание: Это старый вопрос. С Линкпад 5 у вас были ограничения, которые я описал ниже, потому что он не написан в .NET Core. Но теперь вы можете использовать более новый Линкпад 6 или 7, который полностью поддерживает Entity Framework Core, включая драйверы для нескольких систем баз данных.


Я хочу анализировать запросы Entity Framework Core,, который я скопировал из существующего кода в LinqPad, например

UserQuery this_context;
void Main()
{
    this_context = this;
    var validationResult = (

        from ProjectInfo pi in this_context.GetAll<ProjectInfo>()
        join GeneralInformation gi in this_context.GetAll<GeneralInformation>() 
                                   on pi.Id equals gi.Id into gpi
        from gps in gpi.DefaultIfEmpty()

        select new { ... }).ToList();
}

Я знаю, что Linqpad не поддерживает .NET Core,, поэтому мне нужно немного его настроить - для этого я создал метод расширения следующим образом:

public static class Ext
{
    public static  IEnumerable GetAll<T>(this UserQuery uq)
    where T: new()
    {
        return GetAll(uq, new T());
    }

    private static  IEnumerable GetAll<T>(this UserQuery uq, T a)
    {
        switch (a)
        {
            case ProjectInfo v:
                return uq.ProjectInfo.Select(s => s);
            case GeneralInformation v:
                return uq.GeneralInformation.Select(s => s);

            // ... many more cases like the above 

            default: // unknown type
                throw new TypeAccessException($"Unsupported type {a.GetType().FullName}");
        }
    }
    
}

Для получения типа требуется перегруженная функция GetAll — она просто создает пустой новый объект и передает его, чтобы оператор switch мог правильно вывести правильный тип и вернуть правильный запрос.

Это прекрасно работает, но много усилий вставлять каждый тип в оператор switch — это много усилий.

Итак, мой вопрос:

Как этого можно достичь более разумным способом, т. е. без необходимости указывать каждый отдельный тип сущности?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
498
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Объект LINQPad UserQuery, похоже, имеет именно тот метод, который вам нужен:

public static class Ext {
    public static IEnumerable GetAll<T>(this UserQuery uq) =>uq.GetTable(typeof(T));
}

Я считаю, что вы могли бы оставаться в безопасности с помощью:

public static IQueryable<T> GetAll<T>(this UserQuery uq) => (IQueryable<T>)uq.GetTable(typeof(T));

Использование вашей исходной версии IEnumerable приводит к тому, что все таблицы загружаются в память одна за другой, а затем LINQ выполняется для объектов. Использование IQueryable<T> переводит запрос в SQL — это может быть нежелательно в тех случаях, когда перевод LINQ to SQL и EF различается (без уважительной причины), но я мог видеть проблемы со специфическими возможностями EF (например, Include и DbFunctions, хотя у меня есть написаны пустые Include методы расширения, чтобы скрыть некоторые).

Если версия IQueryable не работает, версия ITable<> может:

public static ITable<T> GetAll<T>(this UserQuery uq) where T : class => (ITable<T>)uq.GetTable(typeof(T));

Работает отлично, это было именно то, что я искал. Большое спасибо! Однако типобезопасная версия выдает InvalidOperationException по неизвестной причине.

Matt 24.04.2019 09:14

Возможно, после .AsQueryable() нужен GetTable? Я не получаю сообщение об ошибке, когда тестирую его с помощью подключения к MS SQL. Я добавил еще одну версию typesafe, которая может работать лучше.

NetMage 24.04.2019 21:01

Обе типизированные версии выдают InvalidOperationException: Could not translate expression 'Table(ProjectInfo).Cast().GroupJoin(Table(GeneralInformatio‌​n).Cast(), pi => pi.Id ... в моем случае, а нетипизированная версия (1-я в вашем ответе) работает нормально

Matt 29.04.2019 12:48

Наконец-то я нашел способ заставить его работать с типизированным результатом: public static IEnumerable<T> GetAll<T>(this UserQuery uq) => (IEnumerable<T>)uq.GetTable(typeof(T)); - это работает нормально, поэтому причина в том, что классы интерфейса IQueryable<T> и ITable<T> не на 100% совместимы с Linq.

Matt 29.04.2019 12:52

@ Matt Я не думаю, что это правильно - IQueryable<T> является основой LINQ (для SQL / EF). Если вы приведете к IEnumerable<T>, я буду обеспокоен тем, что вы загружаете всю таблицу в память и выполняете не SQL-запрос, а скорее LINQ to Objects, которые могут немного отличаться.

NetMage 29.04.2019 19:55

Это только для быстрого анализа в Linqpad, а не для целей оптимизации. Я согласен, что предпочел бы IQeryable<T>, но для моего запроса это не работает.

Matt 30.04.2019 20:06

Другие вопросы по теме