Bagaimana cara melakukan grup bergabung dalam .NET Core 3.0 Entity Framework?

13

Dengan perubahan pada .NET Core 3.0 saya mendapatkan

... NavigationExpandingExpressionVisitor 'gagal. Ini mungkin mengindikasikan bug atau batasan di EF Core. Lihat https://go.microsoft.com/fwlink/?linkid=2101433 untuk informasi lebih rinci.) ---> System.InvalidOperationException: Pemrosesan ekspresi LINQ 'GroupJoin, ...

Ini adalah permintaan yang sangat sederhana sehingga harus ada cara untuk melakukannya di .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();

Saya pada dasarnya mencari kueri Linq (atau sintaksis metode seperti di atas) yang akan menggabungkan Studi ke Pasien, dan menetapkan Studi ke daftar kosong atau nol jika tidak ada studi untuk pasien yang diberikan.

Ada ide? Ini bekerja di .NET Core 2.2. Juga tautan MSFT di atas menyebutkan bahwa perubahan kunci terkait dengan evaluasi sisi klien dan menghindari bahwa kueri yang dihasilkan membaca seluruh tabel yang kemudian harus bergabung atau difilter sisi klien. Namun dengan permintaan sederhana ini, bergabung harus sisi server mudah dilakukan.

shelbypereira
sumber

Jawaban:

11

Seperti yang dibahas di sini , Anda mencoba kueri yang tidak didukung oleh database. EF Core 2 menggunakan evaluasi sisi klien untuk membuat kode Anda bekerja, tetapi EF Core 3 menolak, karena kenyamanan sisi klien datang pada biaya masalah kinerja yang sulit untuk debug ketika dataset meningkat.

Anda dapat menggunakan yang digunakan DefaultIfEmptyuntuk bergabung dengan studi pasien dan kemudian mengelompokkannya secara manual 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

Contoh di atas mengambil entitas Pasien dan Studi penuh, tetapi Anda dapat memilih kolom ceri sebagai gantinya. Jika data yang Anda butuhkan dari Pasien terlalu besar untuk diulang untuk setiap Studi, dalam kueri yang bergabung pilih hanya ID Pasien, kueri sisa data Pasien dalam kueri yang tidak tergabung yang terpisah.

Edward Brey
sumber
2
Jawabannya berhasil! Saya kira masih ada beberapa pekerjaan yang harus dilakukan di penerjemah kueri. Kueri sederhana seperti ini harus diterjemahkan. Seharusnya tidak ada masalah kinerja untuk gabungan kelompok sederhana dari 2 tabel karena peningkatan dataset dengan asumsi FK / indeks benar. Saya curiga banyak orang akan memiliki masalah ini, grup 2 tabel bergabung cukup standar dan sering digunakan query.
shelbypereira
@ she72 Saya setuju. Sepertinya masalah berasal dari perbedaan dalam bagaimana LINQ dan SQL menggunakan kata kunci "grup". EF Core harus menerjemahkan LINQ groupbymenjadi gabungan kiri di mana hal itu tidak menarik lebih banyak baris dari yang diharapkan. Saya memposting komentar yang sesuai.
Edward Brey
Saya punya pertanyaan tindak lanjut, saya masih mencoba memahami mengapa pengelompokan untuk jenis permintaan ini perlu dilakukan sisi klien, tampaknya keterbatasan kerangka kerja LINQ baru. Untuk kasus di atas, saya tidak melihat risiko apa pun yang memperlambat eksekusi sisi klien dengan cara yang tidak terduga. Bisakah Anda mengklarifikasi?
shelbypereira
1
Dan sebagai tindak lanjut lebih lanjut, perhatian utama adalah: dalam pertanyaan Anda yang dirumuskan ulang yang mengelompokkan sisi klien jika saya memiliki 1000 studi per pasien, saya akan memuat setiap pasien 1000 kali dari DB? apakah ada alternatif untuk memaksa pekerjaan ini dilakukan di DB dan mengembalikan hasil yang dikelompokkan?
shelbypereira
1
@ shev72 Satu-satunya pengelompokan yang dipahami oleh basis data melibatkan agregat, misalnya kueri pasien dengan jumlah studi per pasien. Basis data selalu mengembalikan dataset persegi panjang. Pengelompokan hierarkis harus disusun oleh klien. Anda bisa melihatnya sebagai evaluasi sisi klien atau sebagai bagian dari ORM . Dalam pengelompokan hierarkis, data entitas induk diulangi, meskipun tidak diminta kembali.
Edward Brey
0

Persis masalah yang sama dan perjuangan besar dengannya. Ternyata .net Core 3.0 tidak mendukung Bergabung atau Groupjoin dalam sintaks metode (belum?). Bagian yang menyenangkan adalah, itu berhasil dalam sintaks Query.

Coba ini, ini sintaks kueri dengan sedikit sintaks metode. Ini diterjemahkan dengan baik ke kueri SQL yang benar dengan gabungan luar kiri yang bagus dan diproses pada basis data. Saya belum punya model sehingga Anda perlu memeriksa sintaksnya sendiri ....

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();
hwmaat
sumber
Omong-omong, Gabung dan GroupJoin dengan Metode syntac DO bekerja dengan Kerangka kerja non-inti dan EF. Dan terjemahkan ke permintaan yang tepat yaitu sisi server yang
diposisikan
1
apa yang dipelajari dalam studi. Pilih (s1 => s1)
Ankur Arora
Model tidak dimasukkan dalam pertanyaan jadi saya tidak tahu model studi. Tebakan terbaik saya adalah bahwa ini adalah koleksi virtual dalam model.
hwmaat