类之间有多个关联
场景
很多ORM框架都支持关联的持久化与反持久化,比如EF提供了为关联建模的API,我们看一个例子.老师和班级之间存在"授课"的关联,一个老师可以为多个开放系统授讯,一个班也会有多个授课老师。用EF为这个关联建模,代码如下: 建横之后EF会自动跟踪这类关联实例的变化从而实施持久化;同时也可以反持久化该关联,例如加载Teacher类的属性TaughtClasses、加载Class类的属性Teachers 大多数情况下,两个类之间关联的数量不会超过1个,但也会有例外。我们仍然以都和班级的关系为例,两者之间除了有"授课"关联,在学校组织考试的时候还会存在"监考"的关联。那么,能够使用持久化框架同时处理“授课”和"监考"这两个关联吗?
解决方案
实体模型
/// <summary>
///班级
/// </summary>
public class Class
{
/// <summary>
///班级ID
/// </summary>
private int _classId;
/// <summary>
///学院
/// </summary>
private string _college;
/// <summary>
///班级的监考教师
/// </summary>
private List<Teacher> _invigilateTeachers;
/// <summary>
///编号
/// </summary>
private byte _number;
/// <summary>
///专业
/// </summary>
private string _profession;
/// <summary>
///学生数
/// </summary>
private int _studentCount;
/// <summary>
///班级的任课教师
/// </summary>
private List<Teacher> _teachers;
/// <summary>
///班级ID
/// </summary>
public int ClassId
{
get => _classId;
set => _classId = value;
}
/// <summary>
///专业
/// </summary>
public string Profession
{
get => _profession;
set => _profession = value;
}
/// <summary>
///编号
/// </summary>
public byte Number
{
get => _number;
set => _number = value;
}
/// <summary>
///学院
/// </summary>
public string College
{
get => _college;
set => _college = value;
}
/// <summary>
///学生数
/// </summary>
public int StudentCount
{
get => _studentCount;
set => _studentCount = value;
}
/// <summary>
///班级的任课教师
/// </summary>
public List<Teacher> Teachers
{
get => _teachers;
set => _teachers = value;
}
/// <summary>
///班级的监考教师
/// </summary>
public List<Teacher> InvigilateTeachers
{
get => _invigilateTeachers;
set => _invigilateTeachers = value;
}
}
/// <summary>
///表示监考关系
/// </summary>
public class Invigilating
{
/// <summary>
///班级
/// </summary>
private Class _class;
/// <summary>
///教师
/// </summary>
private Teacher _teacher;
/// <summary>
///教师
/// </summary>
public Teacher Teacher
{
get => _teacher;
set => _teacher = value;
}
/// <summary>
///班级
/// </summary>
public Class Class
{
get => _class;
set => _class = value;
}
}
/// <summary>
///教师
/// </summary>
public class Teacher
{
/// <summary>
///年龄
/// </summary>
private int _age;
/// <summary>
///教授班级
/// </summary>
private List<Class> _classes;
/// <summary>
///监考的班级
/// </summary>
private List<Class> _invigilateClasses;
/// <summary>
///姓名
/// </summary>
private string _name;
/// <summary>
///职业
/// </summary>
private string _profession;
/// <summary>
///性别
/// </summary>
private bool _sex;
/// <summary>
///教师ID
/// </summary>
private int _teacherId;
/// <summary>
///教师ID
/// </summary>
public int TeacherId
{
get => _teacherId;
set => _teacherId = value;
}
/// <summary>
///姓名
/// </summary>
public string Name
{
get => _name;
set => _name = value;
}
/// <summary>
///职业
/// </summary>
public string Profession
{
get => _profession;
set => _profession = value;
}
/// <summary>
///性别
/// </summary>
public bool Sex
{
get => _sex;
set => _sex = value;
}
/// <summary>
///年龄
/// </summary>
public int Age
{
get => _age;
set => _age = value;
}
/// <summary>
///教授班级
/// </summary>
public List<Class> Classes
{
get => _classes;
set => _classes = value;
}
/// <summary>
///监考的班级
/// </summary>
public List<Class> InvigilateClasses
{
get => _invigilateClasses;
set => _invigilateClasses = value;
}
}
/// <summary>
///表示授课关系
/// </summary>
public class Teaching
{
/// <summary>
///班级
/// </summary>
private Class _class;
/// <summary>
///教师
/// </summary>
private Teacher _teacher;
/// <summary>
///教师
/// </summary>
public Teacher Teacher
{
get => _teacher;
set => _teacher = value;
}
/// <summary>
///班级
/// </summary>
public Class Class
{
get => _class;
set => _class = value;
}
}
模型配置
public class CustomImplicitConfiguration : MySqlContextConfigProvider
{
/// <summary>由派生类实现,获取数据库连接字符串。</summary>
protected override string ConnectionString => Configuration.MySqlConnectionString;
/// <summary>获取一个值,该值指示是否启用存储结构映射</summary>
protected override bool EnableStructMapping => true;
/// <summary>使用指定的建模器创建对象数据模型。</summary>
/// <param name="modelBuilder"></param>
protected override void CreateModel(ModelBuilder modelBuilder)
{
//配置班级实体型
var classEntity = modelBuilder.Entity<Class>();
//配置主键
classEntity.HasKeyAttribute(p => p.ClassId).HasKeyIsSelfIncreased(true);
//配置教师实体型
var teacherEntity = modelBuilder.Entity<Teacher>();
//配置主键
teacherEntity.HasKeyAttribute(p => p.TeacherId).HasKeyIsSelfIncreased(true);
//两个类之间有多种隐式关系 那就配置两个不同的隐式关联型
//配置教师与班级间的表示教授关系的关联型
//注意此处的Teaching类为定义的隐式关联型类 类内除了关联端的引用外不应该存在属性
var classTeacherAssociation1 = modelBuilder.Association<Teaching>();
//此处关联型上无属性为隐式关联型 故 需要指定HasVisible(false)
classTeacherAssociation1.HasVisible(false);
//配置关联端 Class端为Class 在关联表中Class的主键ClassId映射为ClassId
classTeacherAssociation1.AssociationEnd(p => p.Class).HasMapping("ClassId", "ClassId");
//配置关联端 Teacher端为Teacher 在关联表中Teacher的主键TeacherId映射为TeacherId
classTeacherAssociation1.AssociationEnd(p => p.Teacher).HasMapping("TeacherId", "TeacherId");
//多对多 独立映射表
classTeacherAssociation1.ToTable("Teaching");
//配置教师与班级间的表示监考关系的关联型
//注意此处的Invigilating类为定义的隐式关联型类 类内除了关联端的引用外不应该存在属性
var classTeacherAssociation2 = modelBuilder.Association<Invigilating>();
//此处关联型上无属性为隐式关联型 故需要指定HasVisible(false)
classTeacherAssociation2.HasVisible(false);
//配置关联端 Class端为Class 在关联表中Class的主键ClassId映射为ClassId
classTeacherAssociation2.AssociationEnd(p => p.Class).HasMapping("ClassId", "ClassId");
//配置关联端 Teacher端为Teacher 在关联表中Teacher的主键TeacherId映射为TeacherId
classTeacherAssociation2.AssociationEnd(p => p.Teacher).HasMapping("TeacherId", "TeacherId");
//多对多 独立映射表
classTeacherAssociation2.ToTable("Invigilating");
//配置关联引用 此处有两种关系 所以每个类中也相应的有两个关联引用
//注意此处的关联引用使用了指定关联型的关联引用配置方法 AssociationReference<T>
//左端为自己 即Class 右端为 Teacher
classEntity.AssociationReference<Teaching>("Teachers", true).HasLeftEnd("Class").HasRightEnd("Teacher");
classEntity.AssociationReference<Invigilating>("InvigilateTeachers", true).HasLeftEnd("Class")
.HasRightEnd("Teacher");
//左端为自己 即Teacher 右端为 Class
teacherEntity.AssociationReference<Teaching>("Classes", true).HasLeftEnd("Teacher").HasRightEnd("Class");
teacherEntity.AssociationReference<Invigilating>("InvigilateClasses", true).HasLeftEnd("Teacher")
.HasRightEnd("Class");
}
}