Tidak mungkin untuk membuat hubungan banyak-ke-banyak dengan tabel bergabung khusus. Dalam hubungan banyak-ke-banyak, EF mengelola tabel bergabung secara internal dan tersembunyi. Ini adalah tabel tanpa kelas Entity di model Anda. Untuk bekerja dengan tabel gabungan seperti itu dengan properti tambahan, Anda harus membuat sebenarnya dua hubungan satu-ke-banyak. Itu bisa terlihat seperti ini:
public class Member
{
public int MemberID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<MemberComment> MemberComments { get; set; }
}
public class Comment
{
public int CommentID { get; set; }
public string Message { get; set; }
public virtual ICollection<MemberComment> MemberComments { get; set; }
}
public class MemberComment
{
[Key, Column(Order = 0)]
public int MemberID { get; set; }
[Key, Column(Order = 1)]
public int CommentID { get; set; }
public virtual Member Member { get; set; }
public virtual Comment Comment { get; set; }
public int Something { get; set; }
public string SomethingElse { get; set; }
}
Jika sekarang Anda ingin menemukan semua komentar anggota dengan LastName
= "Smith" misalnya, Anda dapat menulis kueri seperti ini:
var commentsOfMembers = context.Members
.Where(m => m.LastName == "Smith")
.SelectMany(m => m.MemberComments.Select(mc => mc.Comment))
.ToList();
... atau ...
var commentsOfMembers = context.MemberComments
.Where(mc => mc.Member.LastName == "Smith")
.Select(mc => mc.Comment)
.ToList();
Atau untuk membuat daftar anggota dengan nama "Smith" (kami menganggap ada lebih dari satu) bersama dengan komentar mereka, Anda dapat menggunakan proyeksi:
var membersWithComments = context.Members
.Where(m => m.LastName == "Smith")
.Select(m => new
{
Member = m,
Comments = m.MemberComments.Select(mc => mc.Comment)
})
.ToList();
Jika Anda ingin menemukan semua komentar anggota dengan MemberId
= 1:
var commentsOfMember = context.MemberComments
.Where(mc => mc.MemberId == 1)
.Select(mc => mc.Comment)
.ToList();
Sekarang Anda juga dapat memfilter menurut properti di tabel bergabung Anda (yang tidak mungkin terjadi dalam hubungan banyak ke banyak), misalnya: Saring semua komentar anggota 1 yang memiliki 99 properti Something
:
var filteredCommentsOfMember = context.MemberComments
.Where(mc => mc.MemberId == 1 && mc.Something == 99)
.Select(mc => mc.Comment)
.ToList();
Karena memuat malas mungkin menjadi lebih mudah. Jika Anda telah memuat Member
Anda harus bisa mendapatkan komentar tanpa permintaan eksplisit:
var commentsOfMember = member.MemberComments.Select(mc => mc.Comment);
Saya kira pemuatan malas akan mengambil komentar secara otomatis di belakang layar.
Edit
Hanya untuk bersenang-senang beberapa contoh lebih banyak cara menambahkan entitas dan hubungan dan cara menghapusnya dalam model ini:
1) Buat satu anggota dan dua komentar dari anggota ini:
var member1 = new Member { FirstName = "Pete" };
var comment1 = new Comment { Message = "Good morning!" };
var comment2 = new Comment { Message = "Good evening!" };
var memberComment1 = new MemberComment { Member = member1, Comment = comment1,
Something = 101 };
var memberComment2 = new MemberComment { Member = member1, Comment = comment2,
Something = 102 };
context.MemberComments.Add(memberComment1); // will also add member1 and comment1
context.MemberComments.Add(memberComment2); // will also add comment2
context.SaveChanges();
2) Tambahkan komentar ketiga member1:
var member1 = context.Members.Where(m => m.FirstName == "Pete")
.SingleOrDefault();
if (member1 != null)
{
var comment3 = new Comment { Message = "Good night!" };
var memberComment3 = new MemberComment { Member = member1,
Comment = comment3,
Something = 103 };
context.MemberComments.Add(memberComment3); // will also add comment3
context.SaveChanges();
}
3) Buat anggota baru dan hubungkan dengan komentar2 yang ada:
var comment2 = context.Comments.Where(c => c.Message == "Good evening!")
.SingleOrDefault();
if (comment2 != null)
{
var member2 = new Member { FirstName = "Paul" };
var memberComment4 = new MemberComment { Member = member2,
Comment = comment2,
Something = 201 };
context.MemberComments.Add(memberComment4);
context.SaveChanges();
}
4) Buat hubungan antara member2 yang ada dan comment3:
var member2 = context.Members.Where(m => m.FirstName == "Paul")
.SingleOrDefault();
var comment3 = context.Comments.Where(c => c.Message == "Good night!")
.SingleOrDefault();
if (member2 != null && comment3 != null)
{
var memberComment5 = new MemberComment { Member = member2,
Comment = comment3,
Something = 202 };
context.MemberComments.Add(memberComment5);
context.SaveChanges();
}
5) Hapus hubungan ini lagi:
var memberComment5 = context.MemberComments
.Where(mc => mc.Member.FirstName == "Paul"
&& mc.Comment.Message == "Good night!")
.SingleOrDefault();
if (memberComment5 != null)
{
context.MemberComments.Remove(memberComment5);
context.SaveChanges();
}
6) Hapus member1 dan semua hubungannya dengan komentar:
var member1 = context.Members.Where(m => m.FirstName == "Pete")
.SingleOrDefault();
if (member1 != null)
{
context.Members.Remove(member1);
context.SaveChanges();
}
Ini juga menghapus hubungan MemberComments
karena hubungan satu-ke-banyak antara Member
dan MemberComments
dan di antara Comment
dan MemberComments
diatur dengan penghapusan cascading oleh konvensi. Dan ini terjadi karena MemberId
dan CommentId
dalam MemberComment
terdeteksi sebagai properti kunci asing untuk Member
dan Comment
navigasi properti dan karena properti FK bertipe non-nullable int
hubungan diperlukan yang akhirnya menyebabkan cascading-delete-setup. Masuk akal dalam model ini, saya pikir.
OnModelCreating
. Contoh ini hanya bergantung pada konvensi pemetaan dan anotasi data.MemberId
danCommentId
kolom dan bukan kolom ketiga tambahanMember_CommentId
(atau sesuatu seperti itu) - yang berarti Anda tidak memiliki nama yang cocok persis di seberang objek untuk kunci AndaJawaban yang sangat bagus dari Slauma.
Saya hanya akan memposting kode untuk melakukan ini menggunakan pemetaan API yang lancar .
Di
DbContext
kelas turunan Anda, Anda bisa melakukan ini:Ini memiliki efek yang sama dengan jawaban yang diterima, dengan pendekatan yang berbeda, yang tidak lebih baik atau lebih buruk.
EDIT:
Saya telah mengubah CreatedDate dari bool ke DateTime.EDIT 2: Karena kurangnya waktu saya telah menempatkan contoh dari aplikasi yang saya kerjakan untuk memastikan ini berfungsi.
sumber
In your classes you can easily describe a many to many relationship with properties that point to each other.
diambil dari: msdn.microsoft.com/en-us/data/hh134698.aspx . Julie Lerman tidak mungkin salah.Comments
properti diMember
. Dan Anda tidak bisa memperbaikinya dengan mengganti namaHasMany
panggilan menjadiMemberComments
karenaMemberComment
entitas tidak memiliki koleksi terbalik untukWithMany
. Sebenarnya Anda perlu mengonfigurasi dua hubungan satu-ke-banyak untuk mendapatkan pemetaan yang tepat.@Esteban, kode yang Anda berikan benar, terima kasih, tetapi tidak lengkap, saya sudah mengujinya. Ada properti yang hilang di kelas "UserEmail":
Saya memposting kode yang telah saya uji jika seseorang tertarik. Salam
sumber
Saya ingin mengusulkan solusi di mana kedua rasa konfigurasi banyak-ke-banyak dapat dicapai.
"Tangkapan" adalah kita perlu membuat tampilan yang menargetkan Tabel Bergabung, karena EF memvalidasi bahwa tabel skema mungkin dipetakan paling banyak satu kali per
EntitySet
.Jawaban ini menambah apa yang sudah dikatakan dalam jawaban sebelumnya dan tidak mengesampingkan salah satu dari pendekatan itu, itu dibangun di atas mereka.
Model:
Konfigurasi:
Isi:
Dari (@Saluma) Saluma ini jawabannya
Ini masih berfungsi ...
... tapi sekarang juga bisa ...
Ini masih berfungsi ...
... tapi sekarang juga bisa ...
Jika Anda ingin menghapus komentar dari anggota
Jika Anda ingin
Include()
komentar anggotaIni semua terasa seperti gula sintaksis, tetapi itu memberi Anda beberapa tunjangan jika Anda mau melalui konfigurasi tambahan. Either way Anda tampaknya bisa mendapatkan yang terbaik dari kedua pendekatan.
sumber
EntityTypeConfiguration<EntityType>
kunci dan properti dari tipe entitas. MisalnyaProperty(x => x.MemberID).HasColumnType("int").IsRequired();
sepertinya berlebihanpublic int MemberID { get; set; }
. Bisakah Anda menghapus pengertian saya yang membingungkan?TLDR; (semi-terkait dengan bug editor EF di EF6 / VS2012U5) jika Anda menghasilkan model dari DB dan Anda tidak dapat melihat tabel m: m: Hapus dua tabel terkait -> Simpan .edmx -> Hasilkan / tambah dari basis data - > Simpan.
Bagi mereka yang datang ke sini bertanya-tanya bagaimana mendapatkan hubungan banyak-ke-banyak dengan kolom atribut untuk ditampilkan dalam file EF .edmx (karena saat ini tidak akan ditampilkan dan diperlakukan sebagai seperangkat properti navigasi), DAN Anda membuat kelas-kelas ini dari tabel basis data Anda (atau basis data-pertama dalam istilah MS, saya percaya.)
Hapus 2 tabel yang dimaksud (untuk mengambil contoh OP, Anggota dan Komentar) di .edmx Anda dan tambahkan lagi melalui 'Buat model dari basis data'. (yaitu jangan mencoba untuk membiarkan Visual Studio memperbaruinya - menghapus, menyimpan, menambah, menyimpan)
Ini kemudian akan membuat tabel ke-3 sesuai dengan apa yang disarankan di sini.
Ini relevan dalam kasus di mana hubungan murni banyak-ke-banyak ditambahkan pada awalnya, dan atribut dirancang dalam DB nanti.
Ini tidak segera jelas dari utas ini / Googling. Jadi, letakkan di sana karena ini adalah tautan # 1 di Google yang mencari masalah tetapi berasal dari sisi DB terlebih dahulu.
sumber
Salah satu cara untuk mengatasi kesalahan ini adalah dengan meletakkan
ForeignKey
atribut di atas properti yang Anda inginkan sebagai kunci asing dan menambahkan properti navigasi.Catatan: Dalam
ForeignKey
atribut, antara tanda kurung dan tanda kutip ganda, tempatkan nama kelas yang dimaksud dengan cara ini.sumber