Entity framework 只是好奇:实体框架如何确定m:n关系中联接表的命名?
我很好奇实体框架如何确定m:n关系中联接表的命名 背景: 我的学生和课程如下。在VS解决方案中进行测试时,EF会将联接表生成为StudentCourses 我的问题:为什么EF将联接表生成为StudentCourses而不是CourseStudents?如何确定联接表的命名? 示例代码:Entity framework 只是好奇:实体框架如何确定m:n关系中联接表的命名?,entity-framework,entity-framework-6,Entity Framework,Entity Framework 6,我很好奇实体框架如何确定m:n关系中联接表的命名 背景: 我的学生和课程如下。在VS解决方案中进行测试时,EF会将联接表生成为StudentCourses 我的问题:为什么EF将联接表生成为StudentCourses而不是CourseStudents?如何确定联接表的命名? 示例代码: public class Student { public Student() { this.Courses = new HashSet<Course>();
public class Student
{
public Student()
{
this.Courses = new HashSet<Course>();
}
public int StudentId { get; set; }
[Required]
public string StudentName { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
public class Course
{
public Course()
{
this.Students = new HashSet<Student>();
}
public int CourseId { get; set; }
public string CourseName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
公共班级学生
{
公立学生()
{
this.Courses=newhashset();
}
公共int StudentId{get;set;}
[必需]
公共字符串StudentName{get;set;}
公共虚拟ICollection课程{get;set;}
}
公共课
{
公共课程()
{
this.Students=newhashset();
}
public int CourseId{get;set;}
公共字符串CourseName{get;set;}
公共虚拟ICollection学生{get;set;}
}
我无法完全找到它,但这是开始
当DbContext创建其模型时,调用。这有一个参数,它是一个
此DbModelBuilder的类型为。
你会以为我们就快到了。遗憾的是,ConventionsConfiguration没有访问约定的属性
如果查看,您可以看到使用v2conventionstart.conventions
初始化约定。你必须做一些深入的挖掘,但你会发现,这是源于。绝大多数约定都在v1约定集中
唉,尽管ConventionSet中约定的名称是相当描述性的,但我找不到定义如何定义连接表名称的约定
使用反射,您可以看到ConventionConfiguration有一些非公共字段
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var conventions = modelBuilder.Conventions;
var conventionsType = conventions.GetType();
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
var fields = conventionsType.GetFields(flags);
foreach (var field in fields)
{
var conventionValue = field.GetValue(conventions);
if (conventionValue is IEnumerable sequence)
{
foreach (var item in sequence)
{
Console.WriteLine(item);
}
}
}
}
这也没有多大帮助,您只能看到这些约定是我们在v2conventioninite中找到的约定。如果你检查一下这些约定,你可能会发现一个组合了这些名称的约定。也许是定义复数名称的那个
无论如何,您可以添加自己的约定,然后可以看到发生了什么:
public class JunctionTableConvention : IStoreModelConvention<AssociationType>
{
public void Apply(AssociationType item, DbModel model)
{
var associations = model.ConceptualToStoreMapping.AssociationSetMappings;
foreach (var association in associations)
{
var associationSetEnds = association.AssociationSet.AssociationSetEnds;
association.StoreEntitySet.Table = String.Format("{0}_{1}",
GetTableName(associationSetEnds[0].EntitySet.ElementType),
GetTableName(associationSetEnds[1].EntitySet.ElementType));
}
}
private string GetTableName(EntityType type)
{
var result = System.Text.RegularExpressions.Regex
.Replace(type.Name, ".[A-Z]", m => m.Value[0] + "_" + m.Value[1]);
return result.ToLower();
}
}
在您的程序中:
static void Main(string[] args)
{
using (var dbContext = new SchoolDbContext())
{
dbContext.Database.Initialize(true);
}
}
调试器将显示调用OnModelCreating,其中添加了连接表约定。OnModelCreating返回后,将调用JunctionModel.Apply
我在学生和老师之间有一种多对多的关系。AssociationType是一个{CodeFirstDatabaseSchema.Teacher\u Students\u Source}
我的代码获取AssociationSetMappings。只有一个这样的映射。
此映射有一个StoreEntitySet,它有一个字符串属性表,该表的值为“TeacherStudents”
我的代码获取AssociationSetEnds以查找数据库集的类型,并为此表构造了一个很好的名称。此名称放在association.StoreEntitySet.Table中
因此,另一个惯例已经用“教师学生”来填充这个值。
为了找出是哪个约定做的,我可以一个接一个地删除约定,并查看名称何时更改
但我把它留给你了
当然,另一种方法是查看所有这些约定的参考源,看看哪一个定义了表的名称。感谢您的指导!我也在考虑约定,但没有像你那样深入地追踪它!
static void Main(string[] args)
{
using (var dbContext = new SchoolDbContext())
{
dbContext.Database.Initialize(true);
}
}