Як здійснити приєднання групи до .NET Core 3.0 Entity Framework?


13

Зі змінами до .NET Core 3.0 я отримую

... Помилка NavigationExpandingExpressionVisitor '. Це може вказувати або на помилку, або на обмеження в EF Core. Див. Https://go.microsoft.com/fwlink/?linkid=2101433 для отримання більш детальної інформації.) ---> System.InvalidOperationException: Обробка виразу LINQ 'GroupJoin, ...

Це дійсно простий запит, тому повинен бути спосіб його виконання в .NET CORE 3.0:

 var queryResults1 = await patients
            .GroupJoin(
                _context.Studies,
                p => p.Id,
                s => s.Patient.Id,
                (p, studies) => new 
                {
                    p.DateOfBirth,
                    p.Id,
                    p.Name,
                    p.Sex,
                   Studies =studies.Select(s1=>s1)
                }
            )
            .AsNoTracking().ToListAsync();

Я в основному шукаю запит Linq (або синтаксис методу, як описано вище), який приєднає дослідження до пацієнтів, і встановить дослідження в порожній список або в нуль, якщо для даного пацієнта не буде проведених досліджень.

Будь-які ідеї? Це працювало в .NET Core 2.2. Також посилання MSFT вище згадує, що зміна ключа ключа пов'язана з оцінкою на стороні клієнта та уникаючи того, щоб згенерований запит читав цілі таблиці, які потім повинні бути об'єднані або відфільтровані на стороні клієнта. Однак за допомогою цього простого запиту з'єднання має бути легко виконаним на стороні сервера.

Відповіді:


11

Як обговорювалося тут , ви намагаєтесь виконати запит, який не підтримується базою даних. EF Core 2 використовував оцінку на стороні клієнта для того, щоб ваш код працював, але EF Core 3 відмовляється, оскільки зручність на стороні клієнта виникає за рахунок важких проблем налагодження ефективності у міру збільшення набору даних.

Ви можете використовувати DefaultIfEmptyвліво, щоб приєднатися до досліджень пацієнтів, а потім згрупуватися вручну ToLookup.

var query =
    from p in db.Patients
    join s in db.Studies on p.Id equals s.PatientId into studies
    from s in studies.DefaultIfEmpty()
    select new { Patient = p, Study = s };

var grouping = query.ToLookup(e => e.Patient); // Grouping done client side

Наведений вище приклад охоплює повну сутність пацієнтів та досліджень, але ви можете замість цього вибирати колони. Якщо потрібні вам дані від пацієнта занадто великі для повторення для кожного дослідження, у об'єднаному запиті виберіть лише ідентифікатор пацієнта, запитуючи решту даних пацієнта в окремому непоєднаному запиті.


2
Відповідь працює! Я думаю, що ще потрібно виконати певну роботу в перекладачі запитів. Простий запит, подібний до цього, має бути перекладним. Не повинно виникнути проблем щодо ефективності простого з’єднання групи з 2 таблиць, оскільки збільшення набору даних, припускаючи, що FK / індекси є правильними. Я підозрюю, що багато людей матимуть цю проблему, приєднання до 2-х табличних груп - це досить стандартний і часто використовується запит.
shelbypereira

@ she72 Я згоден. Схоже, проблема пов'язана з різницею в тому, як LINQ і SQL використовують ключове слово "group". EF Core повинен перевести LINQ groupbyв ліві з'єднання, якщо це не відтягує більше рядків, ніж очікувалося. Я відповідно розмістив коментар .
Едвард Брей

У мене є наступне запитання, я все ще намагаюся зрозуміти, чому групування для цього типу запитів потрібно робити клієнтською стороною, здається, обмеженням нової рамки LINQ. У наведеному вище випадку я не бачу жодних ризиків, що це сповільнить виконання клієнтською стороною несподіваних способів. Ви можете уточнити?
shelbypereira

1
І як подальше подальше спостереження головна проблема: у вашому переформульованому запиті, яка група клієнтів, якщо у мене буде 1000 досліджень на пацієнта, я буду завантажувати кожного пацієнта 1000 разів із БД? чи є якась альтернатива, щоб змусити цю роботу виконуватись у БД та повертати згруповані результати?
shelbypereira

1
@ shev72 Єдине розуміння групування бази даних включає агрегати, наприклад, запит пацієнтів із кількістю досліджень на одного пацієнта. База даних завжди повертає прямокутний набір даних. Клієнт повинен складати ієрархічну групування. Ви можете розглядати це як оцінку на стороні клієнта або як частину ORM . В ієрархічному групуванні дані батьківської сутності повторюються, хоча і не запитуються повторно.
Едвард Брей

0

Було точно таке саме питання і велика боротьба з ним. Виявляється, .net Core 3.0 не підтримує Join або Groupjoin у синтаксисі методу (ще?). Приємна частина, однак, вона працює в синтаксисі Query.

Спробуйте це, це синтаксис запитів із синтаксисом трохи методу. Це добре перекладається на правильний запит SQL з гарним лівим зовнішнім з'єднанням і обробляється в базі даних. У мене немає ваших моделей, тому вам потрібно перевірити синтаксис ....

var queryResults1 = 
    (from p in _context.patients
    from s in _context.Studies.Where(st => st.PatientId == p.Id).DefaultIfEmpty()
    select new
    {
        p.DateOfBirth,
        p.Id,
        p.Name,
        p.Sex,
        Studies = studies.Select(s1 => s1)
    }).ToListAsync();

До речі, Join і GroupJoin з методом Syntac DO працюють з непрофільними Framework та EF. І перекладіть на потрібний запит, який розміщено на стороні сервера
hwmaat

1
що таке дослідження в дослідженнях. Виберіть (s1 => s1)
Ankur Arora

Моделі до питання не були включені, тому я не знаю моделі досліджень. Моя найкраща здогадка - це віртуальна колекція в моделі.
hwmaat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.