C# 如何仅与一个实体建立多对多关系?

C# 如何仅与一个实体建立多对多关系?,c#,entity-framework,ef-code-first,C#,Entity Framework,Ef Code First,课程有许多先决条件,同时一门特定的课程可以是许多课程的先决条件。我尝试先使用EF代码建立多对多关系(在OnModelBCreating中),如下所示: modelBuilder.Entity<Course>() .HasMany(e => e.Prerequisites) .WithMany(e => e.Postrequisites) .Map(m => m.ToTab

课程有许多先决条件,同时一门特定的课程可以是许多课程的先决条件。我尝试先使用EF代码建立多对多关系(在OnModelBCreating中),如下所示:

modelBuilder.Entity<Course>()
                .HasMany(e => e.Prerequisites)
                .WithMany(e => e.Postrequisites)
                .Map(m => m.ToTable("CourseRequisiteMappings")
                .MapLeftKey("CourseId").MapRightKey("CourseId")); // EDIT: THIS LINE IS THE PROBLEM. SEE MARKED ANSWER AND MY COMMENT ON IT.
modelBuilder.Entity()
.HasMany(e=>e
.有许多(e=>e.附加条件)
.Map(m=>m.ToTable(“CourseRequestItemAppings”)
.MapLeftKey(“CourseId”).MapRightKey(“CourseId”);//编辑:这一行就是问题所在。请参阅标记的答案和我对它的评论。
此外,课程课程如下:

public class Course
{
    public int CourseId { get; set; }
    public string Name { get; set; }
    public string InstitutionCode { get; set; }     
    public string Description { get; set; }
    public bool IsElective { get; set; }
    public virtual ICollection<Instructor> Instructors { get; set; }
    public virtual ICollection<Student> Students { get; set; }
    public virtual ICollection<Module> Modules { get; set; }
    public virtual ICollection<Course> Prerequisites { get; set; }
    public virtual ICollection<Course> Postrequisites { get; set; }
}
公共课
{
public int CourseId{get;set;}
公共字符串名称{get;set;}
公共字符串机构代码{get;set;}
公共字符串说明{get;set;}
公共布尔是选择的{get;set;}
公共虚拟ICollection指令器{get;set;}
公共虚拟ICollection学生{get;set;}
公共虚拟ICollection模块{get;set;}
公共虚拟ICollection先决条件{get;set;}
公共虚拟ICollection后条件{get;set;}
}
当我实现这个并去更新数据库时,它给了我以下错误:

CourseId:Name:类型中的每个属性名称都必须是唯一的。财产 已定义名称“CourseId”

ModuleId:Name:类型中的每个属性名称必须是唯一的。财产 已定义名称“ModuleId”

CourseCourse:EntityType:EntitySet“CourseCourse”基于类型 未定义键的“CourseCourse”

ModuleModule:EntityType:EntitySet“ModuleModule”基于类型 未定义键的“ModuleModule”

我找不到这样做的例子,这让我相信以下三种情况之一是正确的:

  • 有一种不同的方式来实现这一点,我没有看到
  • 我在正确的轨道上,但由于缺乏EF知识,我忽略了一些事情
  • 我是第一个尝试的人,EF不支持这一点(不太可能)

  • 首先,是否有人知道我如何建立这种关系,即这些错误意味着什么(对#2作出反应)?对于奖励积分,是否有其他更好或更差的方法(有点1)?提前谢谢。

    我想做这样的模特。我知道你只想要一张桌子。但是如果您不这样做,Ef将创建多对多表。不确定什么东西没有经过测试就没有做对。所以无论如何,这里有另一个选择

    public class Course
    {
    public int CourseId { get; set; }
    public string Name { get; set; }
    public string InstitutionCode { get; set; }     
    public string Description { get; set; }
    public bool IsElective { get; set; }
    //nav elements
    public virtual ICollection<Instructor> Instructors { get; set; }
    public virtual ICollection<Student> Students { get; set; }
    public virtual ICollection<Module> Modules { get; set; }
    public virtual ICollection<PreReqCourse> Prerequisites { get; set; }
    // You can Find follow on courses, by accessing PreReqCourse table, but if you felt this navigation offered enough value, create a post req table too. Using same approach.
    // public virtual ICollection<Course> Postrequisites { get; set; } 
    }
    
    public class PreReqCourse
    {
    public virtual int Id {get; set;}
    public virtual int CourseId { get; set; }
    public virtual Course  PreReqForCourse { get; set; } //Nav prop
    }
    
    
    modelBuilder.Entity<Course>()
                .HasMany(e => e.Prerequisites)
                .WithMany();   
    // Leave WithMany empty. You can define in PreReqCourse Table model, you dont need to model from both directions. 
    
    
    modelBuilder.Entity<PreReqCourse>()
                .HasRequired(e => e.PreReqForCourse)
                .HasForeignKey(f => f.CourseId)
                .WithMany(p=>p.PreRequisites);
    
    公共课
    {
    public int CourseId{get;set;}
    公共字符串名称{get;set;}
    公共字符串机构代码{get;set;}
    公共字符串说明{get;set;}
    公共布尔是选择的{get;set;}
    //导航要素
    公共虚拟ICollection指令器{get;set;}
    公共虚拟ICollection学生{get;set;}
    公共虚拟ICollection模块{get;set;}
    公共虚拟ICollection先决条件{get;set;}
    //通过访问PreReqCourse表,您可以找到后续课程,但如果您觉得此导航提供了足够的价值,也可以使用相同的方法创建PostReqCourse表。
    //公共虚拟ICollection后条件{get;set;}
    }
    公开课预科
    {
    公共虚拟整数Id{get;set;}
    公共虚拟整数CourseId{get;set;}
    公共虚拟课程PreReqForCourse{get;set;}//Nav prop
    }
    modelBuilder.Entity()
    .HasMany(e=>e
    .有许多();
    //留下许多空的。您可以在PreReqCourse表模型中定义,不需要从两个方向建模。
    modelBuilder.Entity()
    .HasRequired(e=>e.PreReqForCourse)
    .HasForeignKey(f=>f.CourseId)
    .有许多(p=>p.1);
    
    您的映射几乎是正确的。但您必须理解,在这个框架下,实体框架将创建一个如此调用的连接表来存储多对多关系

    这个连接表只有两个字段,其中包含共同构成主键的外键。显然,这些外键不能有相同的名称。EF足够聪明,可以自己解决,不需要映射。下面是一个工作示例:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Data.Entity;
    
    namespace ManyToManyUnderTheHoodSpike
    {
    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<CourseContext>());
            using (CourseContext context=new CourseContext())
            {
                context.Courses.Add(new Course("Top of the bill")
                {
                    PrerequisiteCourses = new List<Course>() 
                        {
                            new Course("My two cents"),
                            new Course("Counting to two")
                        }
                });
                context.SaveChanges();
            }
        }
    }
    
    public class CourseContext : DbContext
    {
    
        public DbSet<Course> Courses { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }
    
    public class Course
    {
    
        public Course() { }
    
        public  Course(string name)
        {
            Name = name;
        }
    
        public string Name {get;set;}
        public int CourseId{get;set;}
    
        public ICollection<Course> PrerequisiteCourses{get;set;}
        public ICollection<Course> FollowUpCourses{get;set;}
    }
    }
    

    普雷斯托

    没错!我刚想问一下可读性,你就知道了。因此,从字面上说,我做的唯一一件不正确的事情就是对两个映射键使用名称“CourseId”。这就是问题所在:我认为“MapLeft/RighKey”方法需要旧表中键列的名称,而不是新的中间列。最后,你不喜欢我新创造的术语“后置条件”吗=我总是纠正别人的名字,一直认为我可以做得更好;-)“先决条件”确实是必需的。后续课程通常是可选的……那么“必修”呢?
     protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Course>().HasMany(course => course.PrerequisiteCourses)
                .WithMany(course => course.FollowUpCourses)
                .Map(data => data.ToTable("Prerequisites")
                    .MapLeftKey("FollowUpId")
                    .MapRightKey("PrerequisiteId"));
        }