2014-08-28 129 views
0

课程有许多先决条件,同时一门课程可以成为许多课程的先决条件。我一直在使用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. 

而且,这里是课程类:

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

当我实现了这一点,并去更新数据库,它给了我以下错误:

CourseId:Name:一个类型中的每个属性名称必须是唯一的。属性 名称'CourseId'已经定义。

ModuleId:Name:类型中的每个属性名称必须是唯一的。属性 名称'ModuleId'已被定义。

CourseCourse:EntityType:EntitySet'CourseCourse'基于 'CourseCourse',没有定义键。

ModuleModule:EntityType:EntitySet'ModuleModule'基于 'ModuleModule',它没有定义键。

我找不到这样导致我的一个例子,相信以下三个中的一个为真:

  1. 有完成此不同的方式,我不看
  2. 我是在正确的轨道,但忽视的东西上,由于我缺乏知识与EF
  3. 我是第一个尝试和EF不支持此(不太可能)

首先,有人知道我可以如何建立这种关系,即这些错误意味着什么(回应#2)?对于奖励积分,是否有另外一种方法可能会更好或更差(有点儿#1)?提前致谢。

回答

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

如果你运行该代码你有两个表的数据库:CoursesCourseCourses与作为唯一领域Course_IdCourse_Id1

但是,这不是很可读,所以我们要尽量的映射,使之更具可读性:

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

的Presto!

+0

对!我正要问有关可读性的问题,并且你有它。所以字面上我做的唯一不正确的事情是为两个映射的键使用名称“CourseId”。其中存在的问题是:我认为“MapLeft/RighKey”方法需要旧表格上键列的名称,而不是新的中间表格。最后,你不喜欢我最近创造的术语“postrequisite”吗? = P – 2014-08-28 22:02:54

+0

我总是在纠正别人的命名,不断思考我可以做得更好;-)“先决条件”的确是必需的。后续课程通常是可选的... – Dabblernl 2014-08-28 22:05:50

+0

只需要“Requisite”? – 2014-08-28 22:08:38

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); 
相关问题