สร้างรหัสก่อนมากถึงมากด้วยฟิลด์เพิ่มเติมในตารางการเชื่อมโยง


297

ฉันมีสถานการณ์นี้:

public class Member
{
    public int MemberID { get; set; }

    public string FirstName { get; set; }
    public string LastName { get; set; }

    public virtual ICollection<Comment> Comments { get; set; }
}

public class Comment
{
    public int CommentID { get; set; }
    public string Message { get; set; }

    public virtual ICollection<Member> Members { get; set; }
}

public class MemberComment
{
    public int MemberID { get; set; }
    public int CommentID { get; set; }
    public int Something { get; set; }
    public string SomethingElse { get; set; }
}

ฉันจะกำหนดค่าการเชื่อมโยงของฉันกับAPI ได้อย่างคล่องแคล่วได้อย่างไร หรือมีวิธีที่ดีกว่าในการสร้างตารางการเชื่อมโยง

คำตอบ:


524

เป็นไปไม่ได้ที่จะสร้างความสัมพันธ์แบบกลุ่มต่อกลุ่มด้วยตารางการเข้าร่วมที่กำหนดเอง ในความสัมพันธ์แบบกลุ่มต่อกลุ่ม EF จัดการตารางการเข้าร่วมภายในและซ่อนเร้น เป็นตารางที่ไม่มีคลาส Entity ในโมเดลของคุณ หากต้องการทำงานกับตารางการเข้าร่วมที่มีคุณสมบัติเพิ่มเติมคุณจะต้องสร้างความสัมพันธ์แบบหนึ่งต่อหลายสองอย่าง มันอาจมีลักษณะเช่นนี้:

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; }
}

หากตอนนี้คุณต้องการค้นหาความคิดเห็นทั้งหมดของสมาชิกที่มีLastName= "Smith" คุณสามารถเขียนแบบสอบถามแบบนี้:

var commentsOfMembers = context.Members
    .Where(m => m.LastName == "Smith")
    .SelectMany(m => m.MemberComments.Select(mc => mc.Comment))
    .ToList();

... หรือ ...

var commentsOfMembers = context.MemberComments
    .Where(mc => mc.Member.LastName == "Smith")
    .Select(mc => mc.Comment)
    .ToList();

หรือเพื่อสร้างรายชื่อสมาชิกที่มีชื่อ "Smith" (เราถือว่ามีมากกว่าหนึ่ง) พร้อมกับความคิดเห็นของพวกเขาคุณสามารถใช้เส้นโครง:

var membersWithComments = context.Members
    .Where(m => m.LastName == "Smith")
    .Select(m => new
    {
        Member = m,
        Comments = m.MemberComments.Select(mc => mc.Comment)
    })
    .ToList();

หากคุณต้องการค้นหาความคิดเห็นทั้งหมดของสมาชิกด้วยMemberId= 1:

var commentsOfMember = context.MemberComments
    .Where(mc => mc.MemberId == 1)
    .Select(mc => mc.Comment)
    .ToList();

ตอนนี้คุณสามารถกรองตามคุณสมบัติในตารางการเข้าร่วมของคุณ (ซึ่งอาจเป็นไปไม่ได้ในความสัมพันธ์แบบกลุ่มต่อกลุ่ม) ตัวอย่างเช่น: กรองความคิดเห็นทั้งหมดของสมาชิก 1 ที่มีคุณสมบัติ 99 รายการSomething:

var filteredCommentsOfMember = context.MemberComments
    .Where(mc => mc.MemberId == 1 && mc.Something == 99)
    .Select(mc => mc.Comment)
    .ToList();

เนื่องจากสิ่งที่ขี้เกียจโหลดอาจจะง่ายขึ้น หากคุณมีการโหลดMemberคุณควรจะได้รับความคิดเห็นโดยไม่ต้องสอบถามชัดเจน:

var commentsOfMember = member.MemberComments.Select(mc => mc.Comment);

ฉันเดาว่าการโหลดที่ขี้เกียจจะดึงความคิดเห็นโดยอัตโนมัติที่อยู่เบื้องหลัง

แก้ไข

เพื่อความสนุกสนานตัวอย่างเพิ่มเติมวิธีเพิ่มเอนทิตีและความสัมพันธ์และวิธีการลบออกในโมเดลนี้:

1) สร้างหนึ่งสมาชิกและสองความคิดเห็นของสมาชิกนี้:

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) เพิ่มความคิดเห็นที่สามของ 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) สร้างสมาชิกใหม่และเชื่อมโยงกับความคิดเห็นที่มีอยู่ 2:

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) สร้างความสัมพันธ์ระหว่าง member2 ที่มีอยู่และข้อคิดเห็น 3:

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) ลบความสัมพันธ์นี้อีกครั้ง:

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) ลบ member1 และความสัมพันธ์ทั้งหมดไปยังความคิดเห็น:

var member1 = context.Members.Where(m => m.FirstName == "Pete")
    .SingleOrDefault();
if (member1 != null)
{
    context.Members.Remove(member1);
    context.SaveChanges();
}

นี้จะลบความสัมพันธ์ในMemberCommentsเกินไปเพราะความสัมพันธ์แบบหนึ่งต่อหลายระหว่างMemberและMemberCommentsระหว่างCommentและMemberCommentsมีการติดตั้งกับ cascading ลบโดยการประชุม และเป็นกรณีที่เพราะMemberIdและCommentIdในMemberCommentจะถูกตรวจพบว่าเป็นคุณสมบัติที่สำคัญต่างประเทศสำหรับMemberและCommentคุณสมบัตินำทางและตั้งแต่คุณสมบัติ FK เป็นประเภทที่ไม่ใช่ nullable intความสัมพันธ์เป็นสิ่งจำเป็นที่สุดซึ่งเป็นสาเหตุที่ทำให้ซ้อน-ลบการติดตั้ง ฉันคิดว่ามันสมเหตุสมผลสำหรับรุ่นนี้


1
ขอบคุณ. ขอขอบคุณข้อมูลเพิ่มเติมที่คุณให้ไว้
hgdean

7
@hgdean: ฉันได้สแปมตัวอย่างอีกสองสามขออภัยขออภัยมันเป็นแบบจำลองที่น่าสนใจและคำถามเกี่ยวกับหลายต่อหลายคนด้วยข้อมูลเพิ่มเติมในตารางการเข้าร่วมเกิดขึ้นทุกขณะแล้วที่นี่ ตอนนี้ในครั้งต่อไปฉันมีบางสิ่งบางอย่างที่จะเชื่อมโยงไปยัง ... :)
Slauma

4
@Esteban: OnModelCreatingไม่มีแทนที่คือ ตัวอย่างอาศัยการประชุมการทำแผนที่และคำอธิบายประกอบข้อมูลเท่านั้น
Slauma

4
หมายเหตุ: หากคุณใช้วิธีนี้โดยไม่ต้องใช้ Fluent API ตรวจสอบให้แน่ใจว่าคุณตรวจสอบในฐานข้อมูลของคุณว่าคุณมีคีย์ผสมกับMemberIdและCommentIdคอลัมน์และไม่ใช่คอลัมน์ที่สามเพิ่มเติมMember_CommentId(หรืออะไรทำนองนั้น) - ซึ่งหมายความว่าคุณไม่มีชื่อที่ตรงกัน ข้ามวัตถุสำหรับกุญแจของคุณ
Simon_Weaver

3
@Simon_Weaver (หรือใครก็ตามที่อาจรู้คำตอบ) ฉันมีสถานการณ์ที่คล้ายกัน แต่ฉันต้องการที่จะมีคีย์หลัก "MemberCommentID" สำหรับตารางนั้นเป็นไปได้หรือไม่? ขณะนี้ฉันได้รับข้อยกเว้นโปรดดูคำถามของฉันฉันต้องการความช่วยเหลือจริงๆ ... stackoverflow.com/questions/26783934/…
duxfox

97

คำตอบที่ยอดเยี่ยมโดย Slauma

ฉันเพิ่งจะโพสต์รหัสที่จะทำเช่นนี้ได้อย่างคล่องแคล่วโดยใช้APIการทำแผนที่

public class User {
    public int UserID { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }

    public ICollection<UserEmail> UserEmails { get; set; }
}

public class Email {
    public int EmailID { get; set; }
    public string Address { get; set; }

    public ICollection<UserEmail> UserEmails { get; set; }
}

public class UserEmail {
    public int UserID { get; set; }
    public int EmailID { get; set; }
    public bool IsPrimary { get; set; }
}

ในDbContextชั้นเรียนของคุณคุณสามารถทำได้:

public class MyContext : DbContext {
    protected override void OnModelCreating(DbModelBuilder builder) {
        // Primary keys
        builder.Entity<User>().HasKey(q => q.UserID);
        builder.Entity<Email>().HasKey(q => q.EmailID);
        builder.Entity<UserEmail>().HasKey(q => 
            new { 
                q.UserID, q.EmailID
            });

        // Relationships
        builder.Entity<UserEmail>()
            .HasRequired(t => t.Email)
            .WithMany(t => t.UserEmails)
            .HasForeignKey(t => t.EmailID)

        builder.Entity<UserEmail>()
            .HasRequired(t => t.User)
            .WithMany(t => t.UserEmails)
            .HasForeignKey(t => t.UserID)
    }
}

มันมีผลเช่นเดียวกับคำตอบที่ได้รับการยอมรับด้วยวิธีการที่แตกต่างกันซึ่งไม่ดีขึ้นหรือแย่ลง

แก้ไข: ฉันเปลี่ยนวันที่สร้างจาก bool เป็น DateTime

แก้ไข 2: เนื่องจากไม่มีเวลาฉันวางตัวอย่างจากแอปพลิเคชันที่ฉันกำลังทำงานเพื่อให้แน่ใจว่างานนี้


1
ฉันคิดว่ามันผิด คุณกำลังสร้างความสัมพันธ์ M: M ที่นี่ซึ่งต้องเป็น 1: M สำหรับเอนทิตีทั้งสอง
CHS

1
@CHS In your classes you can easily describe a many to many relationship with properties that point to each other.นำมาจาก: msdn.microsoft.com/en-us/data/hh134698.aspx Julie Lerman ไม่ผิดหรอก
เอสเตบัน

1
Esteban การทำแผนที่ความสัมพันธ์ไม่ถูกต้องจริงๆ @CHS พูดถูก Julie Lerman กำลังพูดถึงความสัมพันธ์แบบหลายต่อหลายที่ "จริง" ในขณะที่เรามีตัวอย่างที่นี่สำหรับแบบจำลองที่ไม่สามารถแมปแบบหลายต่อหลายคนได้ การทำแผนที่ของคุณแม้จะไม่รวบรวมเพราะคุณไม่ได้มีคุณสมบัติในComments Memberและคุณก็ไม่สามารถแก้ไขปัญหานี้โดยการเปลี่ยนชื่อHasManyเรียกร้องให้MemberCommentsเพราะกิจการที่ไม่ได้มีการเก็บรวบรวมผกผันสำหรับMemberComment WithManyในความเป็นจริงคุณต้องกำหนดค่าความสัมพันธ์แบบหนึ่งต่อหลายสองรายการเพื่อให้ได้การจับคู่ที่ถูกต้อง
Slauma

2
ขอบคุณ. ฉันทำตามวิธีนี้เพื่อทำแผนที่หลายต่อหลายคน
Thomas.Benz

ฉันไม่รู้ว่าฉัน แต่สิ่งนี้ทำงานได้ดีกับ MySql หากไม่มีผู้สร้าง Mysql จะโยนข้อผิดพลาดให้ฉันเมื่อฉันลองย้ายข้อมูล
Rodrigo Prieto

11

@Esteban รหัสที่คุณให้ไว้ถูกต้องขอบคุณ แต่ไม่สมบูรณ์ฉันได้ทำการทดสอบแล้ว มีคุณสมบัติที่ขาดหายไปในคลาส "UserEmail":

    public UserTest UserTest { get; set; }
    public EmailTest EmailTest { get; set; }

ฉันโพสต์รหัสที่ฉันทดสอบถ้ามีคนสนใจ ความนับถือ

using System.Data.Entity;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;

#region example2
public class UserTest
{
    public int UserTestID { get; set; }
    public string UserTestname { get; set; }
    public string Password { get; set; }

    public ICollection<UserTestEmailTest> UserTestEmailTests { get; set; }

    public static void DoSomeTest(ApplicationDbContext context)
    {

        for (int i = 0; i < 5; i++)
        {
            var user = context.UserTest.Add(new UserTest() { UserTestname = "Test" + i });
            var address = context.EmailTest.Add(new EmailTest() { Address = "address@" + i });
        }
        context.SaveChanges();

        foreach (var user in context.UserTest.Include(t => t.UserTestEmailTests))
        {
            foreach (var address in context.EmailTest)
            {
                user.UserTestEmailTests.Add(new UserTestEmailTest() { UserTest = user, EmailTest = address, n1 = user.UserTestID, n2 = address.EmailTestID });
            }
        }
        context.SaveChanges();
    }
}

public class EmailTest
{
    public int EmailTestID { get; set; }
    public string Address { get; set; }

    public ICollection<UserTestEmailTest> UserTestEmailTests { get; set; }
}

public class UserTestEmailTest
{
    public int UserTestID { get; set; }
    public UserTest UserTest { get; set; }
    public int EmailTestID { get; set; }
    public EmailTest EmailTest { get; set; }
    public int n1 { get; set; }
    public int n2 { get; set; }


    //Call this code from ApplicationDbContext.ConfigureMapping
    //and add this lines as well:
    //public System.Data.Entity.DbSet<yournamespace.UserTest> UserTest { get; set; }
    //public System.Data.Entity.DbSet<yournamespace.EmailTest> EmailTest { get; set; }
    internal static void RelateFluent(System.Data.Entity.DbModelBuilder builder)
    {
        // Primary keys
        builder.Entity<UserTest>().HasKey(q => q.UserTestID);
        builder.Entity<EmailTest>().HasKey(q => q.EmailTestID);

        builder.Entity<UserTestEmailTest>().HasKey(q =>
            new
            {
                q.UserTestID,
                q.EmailTestID
            });

        // Relationships
        builder.Entity<UserTestEmailTest>()
            .HasRequired(t => t.EmailTest)
            .WithMany(t => t.UserTestEmailTests)
            .HasForeignKey(t => t.EmailTestID);

        builder.Entity<UserTestEmailTest>()
            .HasRequired(t => t.UserTest)
            .WithMany(t => t.UserTestEmailTests)
            .HasForeignKey(t => t.UserTestID);
    }
}
#endregion

3

ฉันต้องการเสนอวิธีแก้ปัญหาซึ่งสามารถใช้การกำหนดค่าแบบหลายต่อหลายรสชาติได้

"การจับ" คือเราต้องสร้างมุมมองที่เป้าหมายเข้าร่วมกับตารางตั้งแต่ EF EntitySetตรวจสอบว่าตารางสคีอาจถูกแมปที่มากที่สุดครั้งเดียวต่อ

คำตอบนี้เพิ่มให้กับสิ่งที่ได้กล่าวไปแล้วในคำตอบก่อนหน้านี้และไม่ได้แทนที่วิธีการใด ๆ เหล่านั้น

นางแบบ:

public class Member
{
    public int MemberID { get; set; }

    public string FirstName { get; set; }
    public string LastName { get; set; }

    public virtual ICollection<Comment> Comments { get; set; }
    public virtual ICollection<MemberCommentView> MemberComments { get; set; }
}

public class Comment
{
    public int CommentID { get; set; }
    public string Message { get; set; }

    public virtual ICollection<Member> Members { get; set; }
    public virtual ICollection<MemberCommentView> MemberComments { get; set; }
}

public class MemberCommentView
{
    public int MemberID { get; set; }
    public int CommentID { get; set; }
    public int Something { get; set; }
    public string SomethingElse { get; set; }

    public virtual Member Member { get; set; }
    public virtual Comment Comment { get; set; }
}

การกำหนดค่า:

using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;

public class MemberConfiguration : EntityTypeConfiguration<Member>
{
    public MemberConfiguration()
    {
        HasKey(x => x.MemberID);

        Property(x => x.MemberID).HasColumnType("int").IsRequired();
        Property(x => x.FirstName).HasColumnType("varchar(512)");
        Property(x => x.LastName).HasColumnType("varchar(512)")

        // configure many-to-many through internal EF EntitySet
        HasMany(s => s.Comments)
            .WithMany(c => c.Members)
            .Map(cs =>
            {
                cs.ToTable("MemberComment");
                cs.MapLeftKey("MemberID");
                cs.MapRightKey("CommentID");
            });
    }
}

public class CommentConfiguration : EntityTypeConfiguration<Comment>
{
    public CommentConfiguration()
    {
        HasKey(x => x.CommentID);

        Property(x => x.CommentID).HasColumnType("int").IsRequired();
        Property(x => x.Message).HasColumnType("varchar(max)");
    }
}

public class MemberCommentViewConfiguration : EntityTypeConfiguration<MemberCommentView>
{
    public MemberCommentViewConfiguration()
    {
        ToTable("MemberCommentView");
        HasKey(x => new { x.MemberID, x.CommentID });

        Property(x => x.MemberID).HasColumnType("int").IsRequired();
        Property(x => x.CommentID).HasColumnType("int").IsRequired();
        Property(x => x.Something).HasColumnType("int");
        Property(x => x.SomethingElse).HasColumnType("varchar(max)");

        // configure one-to-many targeting the Join Table view
        // making all of its properties available
        HasRequired(a => a.Member).WithMany(b => b.MemberComments);
        HasRequired(a => a.Comment).WithMany(b => b.MemberComments);
    }
}

บริบท:

using System.Data.Entity;

public class MyContext : DbContext
{
    public DbSet<Member> Members { get; set; }
    public DbSet<Comment> Comments { get; set; }
    public DbSet<MemberCommentView> MemberComments { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Configurations.Add(new MemberConfiguration());
        modelBuilder.Configurations.Add(new CommentConfiguration());
        modelBuilder.Configurations.Add(new MemberCommentViewConfiguration());

        OnModelCreatingPartial(modelBuilder);
     }
}

จากคำตอบของ Saluma (@Saluma)

หากคุณต้องการค้นหาความคิดเห็นทั้งหมดของสมาชิกที่มี LastName = "Smith" เช่นคุณสามารถเขียนแบบสอบถามแบบนี้:

ยังใช้งานได้ ...

var commentsOfMembers = context.Members
    .Where(m => m.LastName == "Smith")
    .SelectMany(m => m.MemberComments.Select(mc => mc.Comment))
    .ToList();

... แต่ตอนนี้อาจเป็น ...

var commentsOfMembers = context.Members
    .Where(m => m.LastName == "Smith")
    .SelectMany(m => m.Comments)
    .ToList();

หรือเพื่อสร้างรายชื่อสมาชิกที่มีชื่อ "Smith" (เราถือว่ามีมากกว่าหนึ่ง) พร้อมกับความคิดเห็นของพวกเขาคุณสามารถใช้เส้นโครง:

ยังใช้งานได้ ...

var membersWithComments = context.Members
    .Where(m => m.LastName == "Smith")
    .Select(m => new
    {
        Member = m,
        Comments = m.MemberComments.Select(mc => mc.Comment)
    })
    .ToList();

... แต่ตอนนี้อาจเป็น ...

var membersWithComments = context.Members
    .Where(m => m.LastName == "Smith")
    .Select(m => new
    {
        Member = m,
        m.Comments
    })
        .ToList();

หากคุณต้องการลบความคิดเห็นจากสมาชิก

var comment = ... // assume comment from member John Smith
var member = ... // assume member John Smith

member.Comments.Remove(comment);

หากคุณต้องการInclude()แสดงความคิดเห็นของสมาชิก

var member = context.Members
    .Where(m => m.FirstName == "John", m.LastName == "Smith")
    .Include(m => m.Comments);

ทั้งหมดนี้ให้ความรู้สึกเหมือนน้ำตาล syntactic แต่คุณจะได้รับผลประโยชน์เพียงเล็กน้อยถ้าคุณเต็มใจที่จะผ่านการกำหนดค่าเพิ่มเติม ไม่ว่าคุณจะใช้วิธีใดเพื่อให้ได้ประโยชน์สูงสุดจากทั้งสองวิธี


ฉันขอขอบคุณที่อ่านง่ายขึ้นเมื่อพิมพ์ข้อความค้นหา LINQ ฉันอาจต้องใช้วิธีนี้ ฉันต้องถาม EF EntitySet จะอัพเดตมุมมองในฐานข้อมูลโดยอัตโนมัติหรือไม่ คุณเห็นด้วยหรือไม่ว่าเรื่องนี้คล้ายกับ [Sugar] ตามที่อธิบายไว้ในแผน EF5.0 หรือไม่? github.com/dotnet/EntityFramework.Docs/blob/master/…
Krptodr

ฉันสงสัยว่าทำไมคุณดูเหมือนจะนิยามใหม่ในEntityTypeConfiguration<EntityType>คีย์และคุณสมบัติของประเภทเอนทิตี เช่นดูเหมือนว่าจะซ้ำซ้อนกับProperty(x => x.MemberID).HasColumnType("int").IsRequired(); public int MemberID { get; set; }คุณช่วยเคลียร์ความเข้าใจที่สับสนของฉันได้ไหม
นาที

0

TLDR; (กึ่งสัมพันธ์กับข้อผิดพลาดบรรณาธิการของ EF ใน EF6 / VS2012U5)ถ้าคุณสร้างแบบจำลองจากฐานข้อมูลและคุณไม่สามารถดูตาราง m: m ประกอบ: ลบสองตารางที่เกี่ยวข้อง -> บันทึก. edmx -> สร้าง / เพิ่มจากฐานข้อมูล - > บันทึก

สำหรับผู้ที่มาที่นี่สงสัยว่าจะได้รับความสัมพันธ์แบบหลายต่อหลายกลุ่มกับคอลัมน์คุณลักษณะเพื่อแสดงในไฟล์ EF. edmx ได้อย่างไร (เนื่องจากจะไม่แสดงและถือเป็นชุดของคุณสมบัติการนำทาง) และคุณสร้างคลาสเหล่านี้ จากตารางฐานข้อมูลของคุณ (หรือฐานข้อมูลแรกใน MS lingo ฉันเชื่อว่า)

ลบ 2 ตารางที่มีปัญหา (เพื่อนำตัวอย่าง OP, สมาชิกและความคิดเห็น) ใน. edmx ของคุณและเพิ่มอีกครั้งผ่าน 'สร้างแบบจำลองจากฐานข้อมูล' (เช่นอย่าพยายามปล่อยให้ Visual Studio อัปเดต - ลบบันทึกเพิ่มบันทึก)

จากนั้นจะสร้างตารางที่ 3 ตามสิ่งที่แนะนำที่นี่

สิ่งนี้มีความเกี่ยวข้องในกรณีที่มีการเพิ่มความสัมพันธ์แบบหลายต่อหลายอย่างบริสุทธิ์ในตอนแรกและแอตทริบิวต์ได้รับการออกแบบในฐานข้อมูลภายหลัง

สิ่งนี้ยังไม่ชัดเจนในทันทีจากเธรด / Google นี้ ดังนั้นเพียงวางไว้ที่นั่นเพราะนี่คือลิงค์ # 1 บน Google เพื่อค้นหาปัญหา แต่มาจากด้าน DB ก่อน


0

วิธีหนึ่งในการแก้ไขข้อผิดพลาดนี้คือการวางForeignKeyแอตทริบิวต์ไว้ด้านบนของคุณสมบัติที่คุณต้องการให้เป็น foreign key และเพิ่มคุณสมบัติการนำทาง

หมายเหตุ: ในแอForeignKeyททริบิวต์ระหว่างวงเล็บและเครื่องหมายคำพูดคู่ให้ใส่ชื่อของคลาสที่อ้างถึงด้วยวิธีนี้

ป้อนคำอธิบายรูปภาพที่นี่


โปรดเพิ่มคำอธิบายเล็กน้อยในคำตอบเนื่องจากลิงค์ที่ให้ไว้อาจไม่พร้อมใช้งานในอนาคต
n4m31ess_c0d3r

2
ควรเป็นชื่อของคุณสมบัติการนำทางแทนที่จะเป็นคลาส
รอน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.