2014-08-28 112 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);