课程有许多先决条件,同时特定课程可以成为许多课程的先决条件。我尝试使用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:名称:类型中的每个属性名称必须是唯一的。属性 名称'CourseId'已经定义。
ModuleId:Name:类型中的每个属性名称必须是唯一的。属性 名称'ModuleId'已经定义。
CourseCourse:EntityType:EntitySet'TourseCourse'基于类型 'CourseCourse'没有定义键。
ModuleModule:EntityType:EntitySet'ModuleModule'基于类型 'ModuleModule'没有定义键。
我找不到这样做的例子,这让我相信以下三个中的一个是真的:
首先,有没有人知道如何建立这种关系,即这些错误意味着什么(响应#2)?对于奖励积分,是否有另一种方式可以做得更好或更差(有点#1)?提前谢谢。
答案 0 :(得分: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);
答案 1 :(得分:1)
您的映射几乎是正确的。但是你必须明白,实体框架会创建一个如此调用的联结表来存储多对多关系。
这个联结表只有两个字段,包含组成主键的外键。显然这些外键不能具有相同的名称.EF足够聪明,可以自行解决,不需要maping。下面是一个工作示例:
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;}
}
}
如果您运行此代码,您将获得一个包含两个表的数据库:Courses
和CourseCourses
,其中包含Course_Id
和Course_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!