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.
Klausa join berguna untuk mengaitkan elemen dari urutan sumber yang berbeda yang tidak memiliki hubungan langsung dalam model objek. Satu-satunya persyaratan adalah bahwa elemen di setiap sumber berbagi beberapa nilai yang dapat dibandingkan untuk kesetaraan. Misalnya, distributor makanan mungkin memiliki daftar pemasok produk tertentu, dan daftar pembeli. Klausa join dapat digunakan, misalnya, untuk membuat daftar pemasok dan pembeli produk tersebut yang semuanya berada di wilayah yang ditentukan yang sama.
Klausa join mengambil dua urutan sumber sebagai input. Elemen dalam setiap urutan harus berupa atau berisi properti yang dapat dibandingkan dengan properti yang sesuai dalam urutan lain. Klausa join membandingkan kunci yang ditentukan untuk kesetaraan dengan menggunakan kata kunci equals khusus. Semua gabungan yang dilakukan oleh klausa join adalah gabungan ekuivalen (equijoins). Bentuk output klausa join tergantung pada jenis gabungan tertentu yang Anda lakukan. Berikut ini adalah tiga jenis gabungan yang paling umum:
Gabungan Dalam
Bergabung dengan grup
Gabungan kiri luar
Gabungan Dalam
Contoh berikut menunjukkan equijoin internal yang sederhana. Kueri ini menghasilkan urutan datar pasangan "nama/kategori produk". String kategori yang sama akan muncul di beberapa elemen. Jika elemen dari categories tidak memiliki productsyang cocok , kategori tersebut tidak akan muncul dalam hasil.
var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { ProductName = prod.Name, Category = category.Name }; //produces flat sequence
Untuk informasi selengkapnya, lihat Melakukan inner join.
Bergabung dengan grup
Klausa join dengan ekspresi into disebut penggabungan grup.
var innerGroupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select new { CategoryName = category.Name, Products = prodGroup };
Gabungan grup menghasilkan urutan hasil hierarkis, yang mengaitkan elemen dalam urutan sumber kiri dengan satu atau beberapa elemen yang cocok dalam urutan sumber sisi kanan. Penggabungan grup tidak memiliki padanan dalam istilah relasional; ini pada dasarnya adalah rangkaian array objek.
Jika tidak ada elemen dari urutan sumber yang tepat yang ditemukan untuk mencocokkan elemen di sumber kiri, klausa join akan menghasilkan array kosong untuk item tersebut. Oleh karena itu, gabungan grup pada dasarnya masih merupakan inner-equijoin kecuali bahwa urutan hasil diatur ke dalam grup.
Jika Anda hanya memilih hasil dari penggabungan grup, Anda dapat mengakses item, tetapi Anda tidak dapat mengidentifikasi kunci yang sesuai. Oleh karena itu, umumnya lebih berguna untuk memilih hasil gabungan grup ke dalam jenis baru yang juga memiliki nama kunci, seperti yang ditunjukkan pada contoh sebelumnya.
Anda juga dapat, tentu saja, menggunakan hasil gabungan grup sebagai generator subkueri lain:
var innerGroupJoinQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from prod2 in prodGroup
where prod2.UnitPrice > 2.50M
select prod2;
Untuk informasi selengkapnya, lihat Lakukan gabungan terkelompok.
Gabungan kiri luar
Dalam gabungan luar kiri, semua elemen dalam urutan sumber kiri dikembalikan, bahkan jika tidak ada elemen yang cocok dalam urutan kanan. Untuk melakukan gabungan luar kiri di LINQ, gunakan metode DefaultIfEmpty dalam kombinasi dengan gabungan grup untuk menentukan elemen sisi kanan default yang akan dihasilkan jika elemen sisi kiri tidak memiliki kecocokan. Anda dapat menggunakan null sebagai nilai default untuk jenis referensi apa pun, atau Anda dapat menentukan jenis default yang ditentukan pengguna. Dalam contoh berikut, jenis default yang ditentukan pengguna ditampilkan:
var leftOuterJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty(new Product { Name = String.Empty, CategoryID = 0 })
select new { CatName = category.Name, ProdName = item.Name };
Untuk informasi selengkapnya, lihat Lakukan left outer join.
Operator sama dengan
Klausa join melakukan sambungan kesetaraan. Dengan kata lain, Anda hanya dapat mencocokkan berdasarkan kesetaraan dua kunci. Jenis perbandingan lain seperti "lebih besar dari" atau "tidak sama" tidak didukung. Untuk memperjelas bahwa semua gabungan merupakan equijoin, klausa join menggunakan kata kunci equals sebagai pengganti operator ==. Kata kunci equals hanya dapat digunakan dalam klausa join dan berbeda dari operator == dengan beberapa cara penting. Saat membandingkan string, equals memiliki kelebihan beban untuk dibandingkan dengan nilai dan operator == menggunakan kesetaraan referensi. Ketika kedua sisi perbandingan memiliki variabel string yang identik, equals dan == mencapai hasil yang sama: true. Itu karena, ketika program mendeklarasikan dua atau lebih variabel string yang setara, pengkompilasi menyimpan semuanya di lokasi yang sama. Ini dikenal sebagai interning. Perbedaan penting lainnya adalah perbandingan null: null equals null dievaluasi sebagai false dengan operator equals, bukan operator == yang mengevaluasinya sebagai true. Terakhir, perilaku cakupan berbeda: dengan equals, kunci kiri menggunakan urutan sumber luar, dan kunci kanan menggunakan sumber dalam. Sumber daya luar hanya berada dalam cakupan di sisi kiri equals dan urutan sumber daya internal hanya dalam cakupan di sisi kanan.
Penggabungan non-ekuivalen (Non-equijoins)
Anda dapat melakukan non-equijoin, gabungan silang, dan operasi gabungan kustom lainnya dengan memakai beberapa klausa from untuk secara mandiri memasukkan urutan baru ke dalam kueri. Untuk informasi selengkapnya, lihat Lakukan operasi gabungan kustom.
Penggabungan pada koleksi objek vs. tabel relasional
Dalam ekspresi kueri LINQ, operasi gabungan dilakukan pada koleksi objek. Koleksi objek tidak dapat "digabungkan" dengan cara yang sama persis dengan dua tabel relasional. Di LINQ, klausa join eksplisit hanya diperlukan ketika dua urutan sumber tidak terikat oleh hubungan apa pun. Saat bekerja dengan LINQ ke SQL, tabel kunci asing diwakili dalam model objek sebagai properti tabel utama. Misalnya, dalam database Northwind, tabel Pelanggan memiliki hubungan kunci asing dengan tabel Pesanan. Saat Anda memetakan tabel ke model objek, kelas Pelanggan memiliki properti Pesanan yang berisi kumpulan Pesanan yang terkait dengan Pelanggan tersebut. Pada dasarnya, penggabungan telah dilakukan untuk Anda.
Untuk informasi selengkapnya tentang mengkueri di seluruh tabel terkait dalam konteks LINQ ke SQL, lihat Cara: Memetakan Hubungan Database.
Kunci komposit
Anda dapat menguji kesetaraan beberapa nilai dengan menggunakan kunci komposit. Untuk informasi selengkapnya, lihat Bergabung dengan menggunakan kunci komposit. Kunci komposit juga dapat digunakan dalam klausa group.
Contoh
Contoh berikut membandingkan hasil inner join, group join, dan left outer join pada sumber data yang sama dengan menggunakan kunci yang sama. Beberapa kode tambahan ditambahkan ke contoh ini untuk mengklarifikasi hasil di tampilan konsol.
class JoinDemonstration
{
#region Data
class Product
{
public required string Name { get; init; }
public required int CategoryID { get; init; }
}
class Category
{
public required string Name { get; init; }
public required int ID { get; init; }
}
// Specify the first data source.
List<Category> categories =
[
new Category {Name="Beverages", ID=001},
new Category {Name="Condiments", ID=002},
new Category {Name="Vegetables", ID=003},
new Category {Name="Grains", ID=004},
new Category {Name="Fruit", ID=005}
];
// Specify the second data source.
List<Product> products =
[
new Product {Name="Cola", CategoryID=001},
new Product {Name="Tea", CategoryID=001},
new Product {Name="Mustard", CategoryID=002},
new Product {Name="Pickles", CategoryID=002},
new Product {Name="Carrots", CategoryID=003},
new Product {Name="Bok Choy", CategoryID=003},
new Product {Name="Peaches", CategoryID=005},
new Product {Name="Melons", CategoryID=005},
];
#endregion
static void Main(string[] args)
{
JoinDemonstration app = new JoinDemonstration();
app.InnerJoin();
app.GroupJoin();
app.GroupInnerJoin();
app.GroupJoin3();
app.LeftOuterJoin();
app.LeftOuterJoin2();
}
void InnerJoin()
{
// Create the query that selects
// a property from each element.
var innerJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { Category = category.ID, Product = prod.Name };
Console.WriteLine("InnerJoin:");
// Execute the query. Access results
// with a simple foreach statement.
foreach (var item in innerJoinQuery)
{
Console.WriteLine("{0,-10}{1}", item.Product, item.Category);
}
Console.WriteLine($"InnerJoin: {innerJoinQuery.Count()} items in 1 group.");
Console.WriteLine(System.Environment.NewLine);
}
void GroupJoin()
{
// This is a demonstration query to show the output
// of a "raw" group join. A more typical group join
// is shown in the GroupInnerJoin method.
var groupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select prodGroup;
// Store the count of total items (for demonstration only).
int totalItems = 0;
Console.WriteLine("Simple GroupJoin:");
// A nested foreach statement is required to access group items.
foreach (var prodGrouping in groupJoinQuery)
{
Console.WriteLine("Group:");
foreach (var item in prodGrouping)
{
totalItems++;
Console.WriteLine(" {0,-10}{1}", item.Name, item.CategoryID);
}
}
Console.WriteLine($"Unshaped GroupJoin: {totalItems} items in {groupJoinQuery.Count()} unnamed groups");
Console.WriteLine(System.Environment.NewLine);
}
void GroupInnerJoin()
{
var groupJoinQuery2 =
from category in categories
orderby category.ID
join prod in products on category.ID equals prod.CategoryID into prodGroup
select new
{
Category = category.Name,
Products = from prod2 in prodGroup
orderby prod2.Name
select prod2
};
//Console.WriteLine("GroupInnerJoin:");
int totalItems = 0;
Console.WriteLine("GroupInnerJoin:");
foreach (var productGroup in groupJoinQuery2)
{
Console.WriteLine(productGroup.Category);
foreach (var prodItem in productGroup.Products)
{
totalItems++;
Console.WriteLine(" {0,-10} {1}", prodItem.Name, prodItem.CategoryID);
}
}
Console.WriteLine($"GroupInnerJoin: {totalItems} items in {groupJoinQuery2.Count()} named groups");
Console.WriteLine(System.Environment.NewLine);
}
void GroupJoin3()
{
var groupJoinQuery3 =
from category in categories
join product in products on category.ID equals product.CategoryID into prodGroup
from prod in prodGroup
orderby prod.CategoryID
select new { Category = prod.CategoryID, ProductName = prod.Name };
//Console.WriteLine("GroupInnerJoin:");
int totalItems = 0;
Console.WriteLine("GroupJoin3:");
foreach (var item in groupJoinQuery3)
{
totalItems++;
Console.WriteLine($" {item.ProductName}:{item.Category}");
}
Console.WriteLine($"GroupJoin3: {totalItems} items in 1 group");
Console.WriteLine(System.Environment.NewLine);
}
void LeftOuterJoin()
{
// Create the query.
var leftOuterQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select prodGroup.DefaultIfEmpty(new Product() { Name = "Nothing!", CategoryID = category.ID });
// Store the count of total items (for demonstration only).
int totalItems = 0;
Console.WriteLine("Left Outer Join:");
// A nested foreach statement is required to access group items
foreach (var prodGrouping in leftOuterQuery)
{
Console.WriteLine("Group:");
foreach (var item in prodGrouping)
{
totalItems++;
Console.WriteLine(" {0,-10}{1}", item.Name, item.CategoryID);
}
}
Console.WriteLine($"LeftOuterJoin: {totalItems} items in {leftOuterQuery.Count()} groups");
Console.WriteLine(System.Environment.NewLine);
}
void LeftOuterJoin2()
{
// Create the query.
var leftOuterQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty()
select new { Name = item == null ? "Nothing!" : item.Name, CategoryID = category.ID };
Console.WriteLine($"LeftOuterJoin2: {leftOuterQuery2.Count()} items in 1 group");
// Store the count of total items
int totalItems = 0;
Console.WriteLine("Left Outer Join 2:");
// Groups have been flattened.
foreach (var item in leftOuterQuery2)
{
totalItems++;
Console.WriteLine("{0,-10}{1}", item.Name, item.CategoryID);
}
Console.WriteLine($"LeftOuterJoin2: {totalItems} items in 1 group");
}
}
/*Output:
InnerJoin:
Cola 1
Tea 1
Mustard 2
Pickles 2
Carrots 3
Bok Choy 3
Peaches 5
Melons 5
InnerJoin: 8 items in 1 group.
Unshaped GroupJoin:
Group:
Cola 1
Tea 1
Group:
Mustard 2
Pickles 2
Group:
Carrots 3
Bok Choy 3
Group:
Group:
Peaches 5
Melons 5
Unshaped GroupJoin: 8 items in 5 unnamed groups
GroupInnerJoin:
Beverages
Cola 1
Tea 1
Condiments
Mustard 2
Pickles 2
Vegetables
Bok Choy 3
Carrots 3
Grains
Fruit
Melons 5
Peaches 5
GroupInnerJoin: 8 items in 5 named groups
GroupJoin3:
Cola:1
Tea:1
Mustard:2
Pickles:2
Carrots:3
Bok Choy:3
Peaches:5
Melons:5
GroupJoin3: 8 items in 1 group
Left Outer Join:
Group:
Cola 1
Tea 1
Group:
Mustard 2
Pickles 2
Group:
Carrots 3
Bok Choy 3
Group:
Nothing! 4
Group:
Peaches 5
Melons 5
LeftOuterJoin: 9 items in 5 groups
LeftOuterJoin2: 9 items in 1 group
Left Outer Join 2:
Cola 1
Tea 1
Mustard 2
Pickles 2
Carrots 3
Bok Choy 3
Nothing! 4
Peaches 5
Melons 5
LeftOuterJoin2: 9 items in 1 group
Press any key to exit.
*/
Komentar
Klausa join yang tidak diikuti oleh into diterjemahkan ke dalam panggilan metode Join. Klausa join yang diikuti oleh into diterjemahkan ke panggilan metode GroupJoin.
Lihat juga
- Kata Kunci Kueri (LINQ)
- Kueri Terpadu Bahasa (LINQ)
- Operasi Gabungan
- klausul kelompok
- Melakukan perintah left outer join
- Melakukan gabungan dalam
- Melakukan gabungan terkelompok
- Mengurutkan hasil dari klausa join
- Bergabung dengan menggunakan kunci komposit
- Sistem database yang kompatibel untuk Visual Studio