C# 如何仅与一个实体建立多对多关系?
课程有许多先决条件,同时一门特定的课程可以是许多课程的先决条件。我尝试先使用EF代码建立多对多关系(在OnModelBCreating中),如下所示: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
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”
我找不到这样做的例子,这让我相信以下三种情况之一是正确的:
首先,是否有人知道我如何建立这种关系,即这些错误意味着什么(对#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"));
}