Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Language Integrated Query (LINQ) berisi banyak operator kompleks, yang menggabungkan beberapa sumber data atau melakukan pemrosesan yang kompleks. Tidak semua operator LINQ memiliki terjemahan yang sesuai di sisi server. Terkadang, kueri dalam satu formulir diterjemahkan ke server tetapi jika ditulis dalam bentuk yang berbeda tidak diterjemahkan meskipun hasilnya sama. Halaman ini menjelaskan beberapa operator kompleks dan variasi yang didukung. Dalam rilis mendatang, kami mungkin mengenali lebih banyak pola dan menambahkan terjemahan yang sesuai. Penting juga untuk diingat bahwa dukungan terjemahan bervariasi di antara penyedia. Kueri tertentu, yang diterjemahkan dalam SqlServer, mungkin tidak berfungsi untuk database SQLite.
Petunjuk / Saran
Anda dapat melihat contoh artikel ini di GitHub.
Bergabung
Operator LINQ Join memungkinkan Anda menyambungkan dua sumber data berdasarkan pemilih kunci untuk setiap sumber, menghasilkan tuple nilai saat kunci cocok. Ini secara alami diterjemahkan ke INNER JOIN
pada database relasional. Meskipun Gabungan LINQ memiliki pemilih kunci eksternal dan internal, database memerlukan satu syarat penggabungan. Jadi EF Core menghasilkan kondisi gabungan dengan membandingkan pemilih kunci luar dengan pemilih kunci dalam untuk kesetaraan.
var query = from photo in context.Set<PersonPhoto>()
join person in context.Set<Person>()
on photo.PersonPhotoId equals person.PhotoId
select new { person, photo };
SELECT [p].[PersonId], [p].[Name], [p].[PhotoId], [p0].[PersonPhotoId], [p0].[Caption], [p0].[Photo]
FROM [PersonPhoto] AS [p0]
INNER JOIN [Person] AS [p] ON [p0].[PersonPhotoId] = [p].[PhotoId]
Selanjutnya, jika pemilih kunci adalah tipe anonim, EF Core menghasilkan kondisi penggabungan untuk membandingkan kesetaraan setiap komponen.
var query = from photo in context.Set<PersonPhoto>()
join person in context.Set<Person>()
on new { Id = (int?)photo.PersonPhotoId, photo.Caption }
equals new { Id = person.PhotoId, Caption = "SN" }
select new { person, photo };
SELECT [p].[PersonId], [p].[Name], [p].[PhotoId], [p0].[PersonPhotoId], [p0].[Caption], [p0].[Photo]
FROM [PersonPhoto] AS [p0]
INNER JOIN [Person] AS [p] ON ([p0].[PersonPhotoId] = [p].[PhotoId] AND ([p0].[Caption] = N'SN'))
GroupJoin
Operator LINQ GroupJoin memungkinkan Anda menyambungkan dua sumber data yang mirip dengan Gabung, tetapi membuat sekelompok nilai dalam untuk mencocokkan elemen luar. Menjalankan kueri seperti contoh berikut menghasilkan hasil Blog
& IEnumerable<Post>
. Karena database (terutama database relasional) tidak memiliki cara untuk mewakili kumpulan objek sisi klien, GroupJoin tidak diterjemahkan ke server dalam banyak kasus. Ini mengharuskan Anda untuk mendapatkan semua data dari server untuk melakukan GroupJoin tanpa pemilih khusus (kueri pertama di bawah). Tetapi jika pemilih membatasi data yang dipilih, mengambil semua data dari server dapat menyebabkan masalah performa (kueri kedua di bawah). Itulah sebabnya EF Core tidak menerjemahkan GroupJoin.
var query = from b in context.Set<Blog>()
join p in context.Set<Post>()
on b.BlogId equals p.BlogId into grouping
select new { b, grouping };
var query = from b in context.Set<Blog>()
join p in context.Set<Post>()
on b.BlogId equals p.BlogId into grouping
select new { b, Posts = grouping.Where(p => p.Content.Contains("EF")).ToList() };
Pilih Banyak
Operator LINQ SelectMany memungkinkan Anda melakukan enumerasi pada pemilih koleksi untuk setiap elemen terluar dan menghasilkan pasangan nilai dari setiap sumber data. Dalam beberapa hal, ini adalah gabungan tetapi tanpa kondisi apa pun sehingga setiap elemen eksternal terhubung dengan elemen dari sumber kumpulan. Bergantung pada bagaimana pemilih koleksi terkait dengan sumber data luar, SelectMany dapat diterjemahkan ke dalam berbagai kueri yang berbeda di sisi server.
Pemilih koleksi tidak mengacu pada elemen luar
Ketika pemilih koleksi tidak mereferensikan apa pun dari sumber luar, hasilnya adalah produk kartesius dari kedua sumber data. Ini diterjemahkan ke CROSS JOIN
dalam database relasional.
var query = from b in context.Set<Blog>()
from p in context.Set<Post>()
select new { b, p };
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
CROSS JOIN [Posts] AS [p]
Pemilih koleksi mereferensikan bagian luar di dalam klausa where
Ketika selektor koleksi memiliki klausa 'where' yang mengacu pada elemen luar, EF Core menerjemahkannya menjadi penggabungan database dan menggunakan predikat sebagai kondisi penggabungan. Biasanya kasus ini muncul saat menggunakan navigasi koleksi pada elemen luar sebagai pemilih koleksi. Jika koleksi kosong untuk elemen luar, maka tidak ada hasil yang akan dihasilkan untuk elemen luar tersebut. Tetapi jika DefaultIfEmpty
diterapkan pada pemilih koleksi, maka elemen luar akan dihubungkan dengan nilai default elemen dalam. Karena perbedaan ini, kueri semacam ini diterjemahkan menjadi INNER JOIN
dalam ketidakadaan DefaultIfEmpty
dan LEFT JOIN
ketika DefaultIfEmpty
diterapkan.
var query = from b in context.Set<Blog>()
from p in context.Set<Post>().Where(p => b.BlogId == p.BlogId)
select new { b, p };
var query2 = from b in context.Set<Blog>()
from p in context.Set<Post>().Where(p => b.BlogId == p.BlogId).DefaultIfEmpty()
select new { b, p };
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
INNER JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
LEFT JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
Selektor koleksi merujuk pada elemen luar dalam kasus tanpa klausa "where"
Saat selektor koleksi mereferensikan elemen luar dari koleksi, yang tidak berada dalam klausa where (seperti kasus di atas), selektor tersebut tidak diterjemahkan ke join basis data. Itulah sebabnya kita perlu mengevaluasi selektor koleksi untuk setiap elemen luar. Ini diterjemahkan ke dalam APPLY
operasi di banyak database relasional. Jika koleksi kosong untuk elemen luar, maka tidak ada hasil yang akan dihasilkan untuk elemen luar tersebut. Tetapi jika DefaultIfEmpty
diterapkan pada pemilih koleksi, maka elemen luar akan dihubungkan dengan nilai default elemen dalam. Karena perbedaan ini, kueri semacam ini diterjemahkan menjadi CROSS APPLY
dalam ketidakadaan DefaultIfEmpty
dan OUTER APPLY
ketika DefaultIfEmpty
diterapkan. Database tertentu seperti SQLite tidak mendukung APPLY
operator sehingga kueri semacam ini mungkin tidak diterjemahkan.
var query = from b in context.Set<Blog>()
from p in context.Set<Post>().Select(p => b.Url + "=>" + p.Title)
select new { b, p };
var query2 = from b in context.Set<Blog>()
from p in context.Set<Post>().Select(p => b.Url + "=>" + p.Title).DefaultIfEmpty()
select new { b, p };
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], ([b].[Url] + N'=>') + [p].[Title] AS [p]
FROM [Blogs] AS [b]
CROSS APPLY [Posts] AS [p]
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], ([b].[Url] + N'=>') + [p].[Title] AS [p]
FROM [Blogs] AS [b]
OUTER APPLY [Posts] AS [p]
Kelompokkan
Operator LINQ GroupBy membuat hasil jenis IGrouping<TKey, TElement>
di mana TKey
dan TElement
bisa menjadi jenis arbitrer apa pun. Selain itu, IGrouping
mengimplementasikan IEnumerable<TElement>
, yang berarti Anda dapat menyusunnya menggunakan operator LINQ apa pun setelah pengelompokan. Karena tidak ada struktur database yang IGrouping
dapat mewakili operator , GroupBy tidak memiliki terjemahan dalam banyak kasus. Ketika operator agregat diterapkan ke setiap grup, yang mengembalikan skalar, operator dapat diterjemahkan ke SQL GROUP BY
dalam database relasional. SQL GROUP BY
juga terbatas. Ini mengharuskan Anda untuk mengelompokkan hanya berdasarkan nilai skalar. Proyeksi hanya dapat berisi pengelompokan kolom kunci atau agregat apa pun yang diterapkan di atas kolom. EF Core mengidentifikasi pola ini dan menerjemahkannya ke server, seperti dalam contoh berikut:
var query = from p in context.Set<Post>()
group p by p.AuthorId
into g
select new { g.Key, Count = g.Count() };
SELECT [p].[AuthorId] AS [Key], COUNT(*) AS [Count]
FROM [Posts] AS [p]
GROUP BY [p].[AuthorId]
EF Core juga menerjemahkan kueri di mana operator agregat pada pengelompokan muncul dalam operator LINQ Where atau OrderBy (atau operator pengurutan lainnya). Ini menggunakan klausa HAVING
di SQL untuk klausa where. Bagian dari kueri sebelum menerapkan operator GroupBy bisa menjadi kueri kompleks apa pun selama dapat diterjemahkan ke server. Selain itu, setelah Anda menerapkan operator agregat pada kueri pengelompokan untuk menghapus pengelompokan dari sumber yang dihasilkan, Anda dapat menyusun di atasnya seperti kueri lainnya.
var query = from p in context.Set<Post>()
group p by p.AuthorId
into g
where g.Count() > 0
orderby g.Key
select new { g.Key, Count = g.Count() };
SELECT [p].[AuthorId] AS [Key], COUNT(*) AS [Count]
FROM [Posts] AS [p]
GROUP BY [p].[AuthorId]
HAVING COUNT(*) > 0
ORDER BY [p].[AuthorId]
Operator agregat yang didukung EF Core adalah sebagai berikut
.JARING | SQL |
---|---|
Rata-rata(x => x.Properti) | AVG(Property) |
Count() | COUNT(*) |
LongCount() | COUNT(*) |
Maks(x => x.Properti) | MAX(Properti) |
Min(x => x.Property) | MIN(Property) |
Sum(x => x.Property) | SUM(Properti) |
Operator agregat tambahan dapat didukung. Periksa dokumen penyedia Anda untuk pemetaan fungsi lainnya.
Meskipun tidak ada struktur database untuk mewakili IGrouping
, dalam beberapa kasus, EF Core 7.0 dan yang lebih baru dapat membuat pengelompokan setelah hasil dikembalikan dari database. Ini mirip dengan cara kerja operator Include
saat menyertakan koleksi terkait. Kueri LINQ berikut menggunakan operator GroupBy untuk mengelompokkan hasil berdasarkan nilai properti Harganya.
var query = context.Books.GroupBy(s => s.Price);
SELECT [b].[Price], [b].[Id], [b].[AuthorId]
FROM [Books] AS [b]
ORDER BY [b].[Price]
Dalam hal ini, operator GroupBy tidak diterjemahkan langsung ke GROUP BY
klausul di SQL, tetapi sebagai gantinya, EF Core membuat pengelompokan data setelah hasil dikembalikan dari server.
Gabungan Kiri
Meskipun Gabungan Kiri bukan operator LINQ, database relasional memiliki konsep Gabungan Kiri yang sering digunakan dalam kueri. Pola tertentu dalam kueri LINQ memberikan hasil yang sama seperti LEFT JOIN
di server. EF Core mengidentifikasi pola tersebut dan menghasilkan yang setara LEFT JOIN
di sisi server. Pola ini melibatkan pembuatan GroupJoin antara kedua sumber data dan kemudian meratakan pengelompokan dengan menggunakan operator SelectMany dengan DefaultIfEmpty pada sumber pengelompokan agar sesuai dengan null ketika bagian dalam tidak memiliki elemen terkait. Contoh berikut menunjukkan seperti apa pola itu dan apa yang dihasilkannya.
var query = from b in context.Set<Blog>()
join p in context.Set<Post>()
on b.BlogId equals p.BlogId into grouping
from p in grouping.DefaultIfEmpty()
select new { b, p };
SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
LEFT JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
Pola di atas membuat struktur kompleks di pohon ekspresi. Karena itu, EF Core mengharuskan Anda untuk meratakan hasil pengelompokan dari operator GroupJoin pada langkah yang dilakukan segera setelah operator tersebut. Bahkan jika GroupJoin-DefaultIfEmpty-SelectMany digunakan tetapi dalam pola yang berbeda, kami mungkin tidak mengidentifikasinya sebagai Gabungan Kiri.