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.
Gabungan dari dua sumber data adalah asosiasi objek dalam satu sumber data dengan objek yang berbagi atribut umum di sumber data lain.
Penting
Sampel ini menggunakan System.Collections.Generic.IEnumerable<T> sumber data. Sumber data berdasarkan System.Linq.IQueryProvider penggunaan System.Linq.IQueryable<T> sumber data dan pohon ekspresi. Pohon ekspresi memiliki batasan pada sintaks C# yang diizinkan. Selain itu, setiap IQueryProvider
sumber data, seperti EF Core dapat memberlakukan lebih banyak batasan. Periksa dokumentasi untuk sumber data Anda.
Bergabung adalah operasi penting dalam kueri yang menargetkan sumber data yang hubungannya satu sama lain tidak dapat diikuti secara langsung. Dalam pemrograman berorientasi objek, bergabung dapat berarti korelasi antara objek yang tidak dimodelkan, seperti arah mundur dari hubungan satu arah. Contoh hubungan satu arah adalah Student
kelas yang memiliki properti jenis Department
yang mewakili utama, tetapi Department
kelas tidak memiliki properti yang merupakan kumpulan Student
objek. Jika Anda memiliki daftar objek Department
dan ingin menemukan semua siswa di setiap departemen, Anda dapat menggunakan operasi gabungan untuk menemukannya.
Metode join yang diberikan oleh kerangka kerja LINQ adalah Join dan GroupJoin. Metode ini melakukan equijoins, atau gabungan yang cocok dengan dua sumber data berdasarkan kesetaraan kunci. (Sebagai perbandingan, Transact-SQL mendukung operator gabungan selain equals
, misalnya operator less than
.) Dalam istilah database relasional, Join mengimplementasikan gabungan dalam, jenis gabungan di mana hanya objek yang memiliki kecocokan di himpunan data lain yang dikembalikan. Metode GroupJoin tidak setara secara langsung dalam istilah database relasional, tetapi mengimplementasikan superset gabungan dalam dan gabungan kiri luar. Gabungan luar kiri adalah gabungan yang mengembalikan setiap elemen sumber data pertama (kiri), meskipun tidak memiliki elemen yang berkorelasi di sumber data lainnya.
Ilustrasi berikut menunjukkan pandangan konseptual dari dua set dan elemen-elemen di dalam set tersebut yang termasuk dalam gabungan dalam atau gabungan luar kiri.
Metode
Nama Metode | Deskripsi | Sintaksis Ekspresi Kueri C# | Informasi Selengkapnya |
---|---|---|---|
Join | Menggabungkan dua urutan berdasarkan fungsi pemilih utama dan mengekstrak pasangan nilai. | join … in … on … equals … |
Enumerable.Join Queryable.Join |
GroupJoin | Menggabungkan dua urutan berdasarkan fungsi pemilih utama dan mengelompokkan kecocokan yang dihasilkan untuk setiap elemen. | join … in … on … equals … into … |
Enumerable.GroupJoin Queryable.GroupJoin |
Catatan
Contoh berikut dalam artikel ini menggunakan sumber data umum untuk area ini.
Masing-masing Student
memiliki tingkat kelas, departemen utama, dan serangkaian skor. A Teacher
juga memiliki City
properti yang mengidentifikasi kampus tempat guru mengadakan kelas. A Department
memiliki nama, dan referensi untuk siapa Teacher
yang menjabat sebagai kepala departemen.
Anda dapat menemukan contoh himpunan data di repositori sumber.
public enum GradeLevel
{
FirstYear = 1,
SecondYear,
ThirdYear,
FourthYear
};
public class Student
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
public required int ID { get; init; }
public required GradeLevel Year { get; init; }
public required List<int> Scores { get; init; }
public required int DepartmentID { get; init; }
}
public class Teacher
{
public required string First { get; init; }
public required string Last { get; init; }
public required int ID { get; init; }
public required string City { get; init; }
}
public class Department
{
public required string Name { get; init; }
public int ID { get; init; }
public required int TeacherID { get; init; }
}
Contoh berikut menggunakan klausa join … in … on … equals …
untuk menggabungkan dua urutan berdasarkan nilai tertentu:
var query = from student in students
join department in departments on student.DepartmentID equals department.ID
select new { Name = $"{student.FirstName} {student.LastName}", DepartmentName = department.Name };
foreach (var item in query)
{
Console.WriteLine($"{item.Name} - {item.DepartmentName}");
}
Kueri sebelumnya dapat diekspresikan menggunakan sintaks metode seperti yang diperlihatkan dalam kode berikut:
var query = students.Join(departments,
student => student.DepartmentID, department => department.ID,
(student, department) => new { Name = $"{student.FirstName} {student.LastName}", DepartmentName = department.Name });
foreach (var item in query)
{
Console.WriteLine($"{item.Name} - {item.DepartmentName}");
}
Contoh berikut menggunakan klausa join … in … on … equals … into …
untuk menggabungkan dua urutan berdasarkan nilai tertentu dan mengelompokkan kecocokan yang dihasilkan untuk setiap elemen:
IEnumerable<IEnumerable<Student>> studentGroups = from department in departments
join student in students on department.ID equals student.DepartmentID into studentGroup
select studentGroup;
foreach (IEnumerable<Student> studentGroup in studentGroups)
{
Console.WriteLine("Group");
foreach (Student student in studentGroup)
{
Console.WriteLine($" - {student.FirstName}, {student.LastName}");
}
}
Kueri sebelumnya dapat diekspresikan menggunakan sintaks metode seperti yang diperlihatkan dalam contoh berikut:
// Join department and student based on DepartmentId and grouping result
IEnumerable<IEnumerable<Student>> studentGroups = departments.GroupJoin(students,
department => department.ID, student => student.DepartmentID,
(department, studentGroup) => studentGroup);
foreach (IEnumerable<Student> studentGroup in studentGroups)
{
Console.WriteLine("Group");
foreach (Student student in studentGroup)
{
Console.WriteLine($" - {student.FirstName}, {student.LastName}");
}
}
Lakukan gabungan dalam
Dalam istilah database relasional, inner join menghasilkan hasil set di mana setiap elemen dalam koleksi pertama muncul satu kali untuk setiap elemen yang cocok dalam koleksi kedua. Jika elemen dalam koleksi pertama tidak memiliki elemen yang cocok, elemen tersebut tidak muncul dalam tataan hasil. Metode Join, yang dipanggil oleh klausul join
di C#, mengimplementasikan gabungan dalam. Contoh berikut menunjukkan kepada Anda cara melakukan empat variasi join dalam.
- Gabungan dalam sederhana yang menghubungkan elemen dari dua sumber data berdasarkan kunci sederhana.
- Inner join yang menghubungkan elemen dari dua sumber data berdasarkan kunci komposit . Kunci komposit, yang merupakan kunci yang terdiri dari lebih dari satu nilai, memungkinkan Anda untuk menghubungkan elemen berdasarkan lebih dari satu properti.
- Gabungan multiple di mana operasi gabungan berturut-turut ditambahkan satu sama lain.
- Gabungan dalam yang diimplementasikan dengan menggunakan gabungan grup.
Gabungan kunci tunggal
Contoh berikut cocok Teacher
dengan objek dengan objek yang Department
cocok dengan TeacherId
.Teacher
Klausa select
dalam C# menentukan tampilan objek yang dihasilkan. Dalam contoh berikut, objek yang dihasilkan adalah jenis anonim yang terdiri dari nama departemen dan nama guru yang memimpin departemen.
var query = from department in departments
join teacher in teachers on department.TeacherID equals teacher.ID
select new
{
DepartmentName = department.Name,
TeacherName = $"{teacher.First} {teacher.Last}"
};
foreach (var departmentAndTeacher in query)
{
Console.WriteLine($"{departmentAndTeacher.DepartmentName} is managed by {departmentAndTeacher.TeacherName}");
}
Anda mencapai hasil yang sama menggunakan Join sintaks metode:
var query = teachers
.Join(departments, teacher => teacher.ID, department => department.TeacherID,
(teacher, department) =>
new { DepartmentName = department.Name, TeacherName = $"{teacher.First} {teacher.Last}" });
foreach (var departmentAndTeacher in query)
{
Console.WriteLine($"{departmentAndTeacher.DepartmentName} is managed by {departmentAndTeacher.TeacherName}");
}
Guru yang bukan kepala departemen tidak muncul di hasil akhir.
Gabungan kunci komposit
Alih-alih menghubungkan elemen hanya berdasarkan satu properti, Anda dapat menggunakan kunci komposit untuk membandingkan elemen berdasarkan beberapa properti. Tentukan fungsi pemilih kunci untuk setiap koleksi untuk mengembalikan jenis anonim yang terdiri dari properti yang ingin Anda bandingkan. Jika Anda memberi label properti, properti tersebut harus memiliki label yang sama di setiap jenis anonim kunci. Properti tersebut juga harus muncul dalam urutan yang sama.
Contoh berikut menggunakan daftar Teacher
objek dan daftar Student
objek untuk menentukan guru mana yang juga siswa. Kedua jenis ini memiliki properti yang mewakili nama depan dan keluarga setiap orang. Fungsi yang membuat kunci join dari setiap elemen daftar mengembalikan tipe anonim yang terdiri atas properti. Operasi gabungan membandingkan kunci komposit ini untuk kesetaraan dan mengembalikan pasangan objek dari setiap daftar di mana nama depan dan nama keluarga cocok.
// Join the two data sources based on a composite key consisting of first and last name,
// to determine which employees are also students.
IEnumerable<string> query =
from teacher in teachers
join student in students on new
{
FirstName = teacher.First,
LastName = teacher.Last
} equals new
{
student.FirstName,
student.LastName
}
select teacher.First + " " + teacher.Last;
string result = "The following people are both teachers and students:\r\n";
foreach (string name in query)
{
result += $"{name}\r\n";
}
Console.Write(result);
Anda dapat menggunakan metode , seperti yang Join ditunjukkan dalam contoh berikut:
IEnumerable<string> query = teachers
.Join(students,
teacher => new { FirstName = teacher.First, LastName = teacher.Last },
student => new { student.FirstName, student.LastName },
(teacher, student) => $"{teacher.First} {teacher.Last}"
);
Console.WriteLine("The following people are both teachers and students:");
foreach (string name in query)
{
Console.WriteLine(name);
}
Gabungan ganda
Sejumlah operasi gabungan dapat saling dihubungkan satu sama lain untuk melakukan gabungan majemuk. Setiap klausa join
dalam C# menghubungkan sumber data tertentu dengan hasil gabungan sebelumnya.
Klausa pertama join
cocok dengan siswa dan departemen berdasarkan objek Student
yang DepartmentID
cocok dengan Department
objek ID
. Ini mengembalikan urutan jenis anonim yang berisi Student
objek dan Department
objek.
Klausa join
kedua mengaitkan tipe anonim yang dikembalikan oleh penggabungan pertama dengan objek Teacher
berdasarkan kecocokan ID guru dengan ID kepala departemen. Ini mengembalikan urutan jenis anonim yang berisi nama siswa, nama departemen, dan nama pemimpin departemen. Karena operasi ini adalah gabungan dalam, hanya objek dari sumber data pertama yang memiliki kecocokan di sumber data kedua yang dikembalikan.
// The first join matches Department.ID and Student.DepartmentID from the list of students and
// departments, based on a common ID. The second join matches teachers who lead departments
// with the students studying in that department.
var query = from student in students
join department in departments on student.DepartmentID equals department.ID
join teacher in teachers on department.TeacherID equals teacher.ID
select new {
StudentName = $"{student.FirstName} {student.LastName}",
DepartmentName = department.Name,
TeacherName = $"{teacher.First} {teacher.Last}"
};
foreach (var obj in query)
{
Console.WriteLine($"""The student "{obj.StudentName}" studies in the department run by "{obj.TeacherName}".""");
}
Yang setara menggunakan beberapa Join metode menggunakan pendekatan yang sama dengan jenis anonim:
var query = students
.Join(departments, student => student.DepartmentID, department => department.ID,
(student, department) => new { student, department })
.Join(teachers, commonDepartment => commonDepartment.department.TeacherID, teacher => teacher.ID,
(commonDepartment, teacher) => new
{
StudentName = $"{commonDepartment.student.FirstName} {commonDepartment.student.LastName}",
DepartmentName = commonDepartment.department.Name,
TeacherName = $"{teacher.First} {teacher.Last}"
});
foreach (var obj in query)
{
Console.WriteLine($"""The student "{obj.StudentName}" studies in the department run by "{obj.TeacherName}".""");
}
Gabungan dalam dengan menggunakan gabungan yang dikelompokkan
Contoh berikut menunjukkan kepada Anda cara menerapkan gabungan dalam dengan menggunakan gabungan grup. Daftar Department
objek digabungkan dengan grup ke daftar Student
objek berdasarkan properti yang Department.ID
Student.DepartmentID
cocok. Gabungan grup membuat kumpulan grup perantara, di mana setiap grup terdiri dari objek Department
dan urutan objek Student
yang cocok. Klausa kedua from
menggabungkan (atau meratakan) urutan urutan ini menjadi satu urutan yang lebih lama. Klausa select
menentukan jenis elemen dalam urutan akhir. Jenis itu adalah jenis anonim yang terdiri dari nama siswa dan nama departemen yang cocok.
var query1 =
from department in departments
join student in students on department.ID equals student.DepartmentID into gj
from subStudent in gj
select new
{
DepartmentName = department.Name,
StudentName = $"{subStudent.FirstName} {subStudent.LastName}"
};
Console.WriteLine("Inner join using GroupJoin():");
foreach (var v in query1)
{
Console.WriteLine($"{v.DepartmentName} - {v.StudentName}");
}
Hasil yang sama dapat dicapai menggunakan GroupJoin metode, sebagai berikut:
var queryMethod1 = departments
.GroupJoin(students, department => department.ID, student => student.DepartmentID,
(department, gj) => new { department, gj })
.SelectMany(departmentAndStudent => departmentAndStudent.gj,
(departmentAndStudent, subStudent) => new
{
DepartmentName = departmentAndStudent.department.Name,
StudentName = $"{subStudent.FirstName} {subStudent.LastName}"
});
Console.WriteLine("Inner join using GroupJoin():");
foreach (var v in queryMethod1)
{
Console.WriteLine($"{v.DepartmentName} - {v.StudentName}");
}
Hasilnya setara dengan kumpulan hasil yang diperoleh dengan menggunakan klausa join
tanpa klausa into
untuk melakukan gabungan dalam. Kode berikut menunjukkan kueri yang setara ini:
var query2 = from department in departments
join student in students on department.ID equals student.DepartmentID
select new
{
DepartmentName = department.Name,
StudentName = $"{student.FirstName} {student.LastName}"
};
Console.WriteLine("The equivalent operation using Join():");
foreach (var v in query2)
{
Console.WriteLine($"{v.DepartmentName} - {v.StudentName}");
}
Untuk menghindari penautan, metode tunggal Join dapat digunakan seperti yang disajikan di sini:
var queryMethod2 = departments.Join(students, departments => departments.ID, student => student.DepartmentID,
(department, student) => new
{
DepartmentName = department.Name,
StudentName = $"{student.FirstName} {student.LastName}"
});
Console.WriteLine("The equivalent operation using Join():");
foreach (var v in queryMethod2)
{
Console.WriteLine($"{v.DepartmentName} - {v.StudentName}");
}
Melakukan gabungan yang dikelompokkan
Gabungan grup berguna untuk menghasilkan struktur data hierarkis. Ini memasangkan setiap elemen dari kumpulan pertama dengan sekumpulan elemen berkorelasi dari kumpulan kedua.
Catatan
Setiap elemen koleksi pertama muncul dalam kumpulan hasil gabungan grup terlepas dari apakah elemen berkorelasi ditemukan di koleksi kedua. Dalam kasus di mana tidak ada elemen berkorelasi yang ditemukan, urutan elemen berkorelasi untuk elemen tersebut kosong. Oleh karena itu, pemilih hasil memiliki akses ke setiap elemen dari kumpulan pertama. Ini berbeda dari pemilih hasil dalam penggabungan non-grup, di mana elemen-elemen dalam koleksi pertama yang tidak cocok di koleksi kedua tidak dapat diakses.
Peringatan
Enumerable.GroupJoin tidak memiliki padanan langsung dalam istilah database hubungan tradisional. Namun, metode ini menerapkan superset gabungan dalam dan gabungan kiri luar. Kedua operasi ini dapat ditulis dalam bentuk gabungan yang dikelompokkan. Untuk informasi selengkapnya, lihat Entity Framework Core, GroupJoin.
Contoh pertama dalam artikel ini menunjukkan kepada Anda cara melakukan penggabungan grup. Contoh kedua menunjukkan kepada Anda cara menggunakan gabungan grup untuk membuat elemen XML.
Bergabung dengan grup
Contoh berikut melakukan gabungan grup objek jenis Department
dan Student
berdasarkan Department.ID
yang cocok dengan properti Student.DepartmentID
. Tidak seperti gabungan non-grup, yang menghasilkan sepasang elemen untuk setiap kecocokan, gabungan grup hanya menghasilkan satu objek yang dihasilkan untuk setiap elemen koleksi pertama, yang dalam contoh ini adalah objek Department
. Elemen terkait dari kumpulan kedua, yang dalam contoh ini adalah objek Student
, dikelompokkan ke dalam kumpulan. Terakhir, fungsi pemilih hasil membuat jenis anonim untuk setiap kecocokan yang terdiri dari Department.Name
dan kumpulan objek Student
.
var query = from department in departments
join student in students on department.ID equals student.DepartmentID into studentGroup
select new
{
DepartmentName = department.Name,
Students = studentGroup
};
foreach (var v in query)
{
// Output the department's name.
Console.WriteLine($"{v.DepartmentName}:");
// Output each of the students in that department.
foreach (Student? student in v.Students)
{
Console.WriteLine($" {student.FirstName} {student.LastName}");
}
}
Dalam contoh di atas, query
variabel berisi kueri yang membuat daftar di mana setiap elemen adalah jenis anonim yang berisi nama departemen dan kumpulan siswa yang belajar di departemen tersebut.
Kueri yang setara menggunakan sintaks metode diperlihatkan dalam kode berikut:
var query = departments.GroupJoin(students, department => department.ID, student => student.DepartmentID,
(department, Students) => new { DepartmentName = department.Name, Students });
foreach (var v in query)
{
// Output the department's name.
Console.WriteLine($"{v.DepartmentName}:");
// Output each of the students in that department.
foreach (Student? student in v.Students)
{
Console.WriteLine($" {student.FirstName} {student.LastName}");
}
}
Bergabung dengan grup untuk membuat XML
Gabungan grup ideal untuk membuat XML menggunakan LINQ ke XML. Contoh berikut ini mirip dengan contoh sebelumnya kecuali bahwa sebagai ganti dari membuat jenis anonim, fungsi pemilih hasil membuat elemen XML yang mewakili objek yang digabungkan.
XElement departmentsAndStudents = new("DepartmentEnrollment",
from department in departments
join student in students on department.ID equals student.DepartmentID into studentGroup
select new XElement("Department",
new XAttribute("Name", department.Name),
from student in studentGroup
select new XElement("Student",
new XAttribute("FirstName", student.FirstName),
new XAttribute("LastName", student.LastName)
)
)
);
Console.WriteLine(departmentsAndStudents);
Kueri yang setara menggunakan sintaks metode diperlihatkan dalam kode berikut:
XElement departmentsAndStudents = new("DepartmentEnrollment",
departments.GroupJoin(students, department => department.ID, student => student.DepartmentID,
(department, Students) => new XElement("Department",
new XAttribute("Name", department.Name),
from student in Students
select new XElement("Student",
new XAttribute("FirstName", student.FirstName),
new XAttribute("LastName", student.LastName)
)
)
)
);
Console.WriteLine(departmentsAndStudents);
Melakukan gabungan kiri luar
Gabungan luar kiri adalah gabungan di mana setiap elemen koleksi pertama dikembalikan, terlepas dari apakah ia memiliki elemen yang berkorelasi dalam koleksi kedua. Anda dapat menggunakan LINQ untuk melakukan gabungan luar kiri dengan memanggil metode DefaultIfEmpty pada hasil gabungan grup.
Contoh berikut menunjukkan cara menggunakan metode DefaultIfEmpty pada hasil dari penggabungan grup untuk melakukan join kiri luar.
Langkah pertama dalam menghasilkan gabungan luar kiri dari dua koleksi adalah melakukan gabungan dalam dengan menggunakan gabungan grup. (Lihat Lakukan gabungan dalam untuk penjelasan tentang proses ini.) Dalam contoh ini, daftar Department
objek digabungkan dalam ke daftar Student
objek berdasarkan Department
ID objek yang cocok dengan siswa DepartmentID
.
Langkah kedua adalah memasukkan setiap elemen dari koleksi pertama (kiri) dalam kumpulan hasil meskipun elemen tersebut tidak memiliki kecocokan dalam koleksi kanan. Ini dicapai dengan memanggil DefaultIfEmpty pada setiap urutan elemen yang cocok dari gabungan grup. Dalam contoh ini, DefaultIfEmpty dipanggil pada setiap serangkai objek Student
yang cocok. Metode mengembalikan koleksi yang berisi nilai default tunggal jika urutan objek yang Student
cocok kosong untuk objek apa pun Department
, memastikan bahwa setiap Department
objek diwakili dalam koleksi hasil.
Catatan
Nilai default untuk jenis referensi adalah null
; oleh karena itu, contoh memeriksa referensi null sebelum mengakses setiap elemen dari setiap koleksi Student
.
var query =
from student in students
join department in departments on student.DepartmentID equals department.ID into gj
from subgroup in gj.DefaultIfEmpty()
select new
{
student.FirstName,
student.LastName,
Department = subgroup?.Name ?? string.Empty
};
foreach (var v in query)
{
Console.WriteLine($"{v.FirstName:-15} {v.LastName:-15}: {v.Department}");
}
Kueri yang setara menggunakan sintaks metode diperlihatkan dalam kode berikut:
var query = students
.GroupJoin(
departments,
student => student.DepartmentID,
department => department.ID,
(student, departmentList) => new { student, subgroup = departmentList })
.SelectMany(
joinedSet => joinedSet.subgroup.DefaultIfEmpty(),
(student, department) => new
{
student.student.FirstName,
student.student.LastName,
Department = department?.Name ?? string.Empty
});
foreach (var v in query)
{
Console.WriteLine($"{v.FirstName:-15} {v.LastName:-15}: {v.Department}");
}