Skip to main content

显式关联

场景

什么是显式关联呢?在面向对象理论中,关联用来描述两个类或者说两种对象)之间的关系,正如对象具有属性一样,关系也可能有属性。 这样的例子很多,比如老师与班级之间的“教学” (Teaching)关系,这是一个显式关联,因为一个老师在不同班级教授的课程可能不同。在面向对象理论中用关联类来(图中Teaching类)表示显式关联专统ORM框架不能直接支持显式关联的映射,必须把关联类(Teaching)改为实体类,并且定义两个关联分别指向Car和Wheel。这样虽然可以正确地向数据库写入数据,但模型的内涵却背离了现实世界,从根本上违反了面向对象理念。

http://indexmp4.suiyiyun.cn/img/image-20231031200131370.png

解决方案

实体模型

 /// <summary>
///班级
/// </summary>
public class Class
{
/// <summary>
///班级ID
/// </summary>
private int _classId;

/// <summary>
///学院
/// </summary>
private string _college;

/// <summary>
///编号
/// </summary>
private byte _number;

/// <summary>
///专业
/// </summary>
private string _profession;

/// <summary>
///学生数
/// </summary>
private int _studentCount;

/// <summary>
///班级的授课
/// </summary>
private List<Teaching> _teachings;

/// <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<Teaching> Teachings
{
get => _teachings;
set => _teachings = value;
}
}
 /// <summary>
///教师
/// </summary>
public class Teacher
{
/// <summary>
///年龄
/// </summary>
private int _age;

/// <summary>
///姓名
/// </summary>
private string _name;

/// <summary>
///职业
/// </summary>
private string _profession;

/// <summary>
///性别
/// </summary>
private bool _sex;

/// <summary>
///教师ID
/// </summary>
private int _teacherId;

/// <summary>
///教授班级
/// </summary>
private List<Teaching> _teachings;

/// <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<Teaching> Teachings
{
get => _teachings;
set => _teachings = value;
}
}
 /// <summary>
///表示授课关系
/// </summary>
public class Teaching
{
/// <summary>
///授课的班级Id
/// </summary>
private readonly int _classId;

/// <summary>
///授课的教师ID
/// </summary>
private readonly int _teacherId;

/// <summary>
///授课的班级
/// </summary>
private Class _class;

/// <summary>
///教授的课程
/// </summary>
private string _course;

/// <summary>
///授课的教师
/// </summary>
private Teacher _teacher;

/// <summary>
///初始化授课关系
/// </summary>
/// <param name="course">所授课程</param>
/// <param name="teacher">授课的教师</param>
/// <param name="class">授课的班级</param>
public Teaching(string course, Teacher teacher, Class @class)
{
_course = course;
_teacher = teacher;
_class = @class;
_teacherId = teacher.TeacherId;
_classId = @class.ClassId;
}

/// <summary>
///反持久化构造函数
/// </summary>
protected Teaching(int teacherId, int classId)
{
_teacherId = teacherId;
_classId = classId;
}

/// <summary>
///教授的课程
/// </summary>
public string Course
{
get => _course;
set => _course = value;
}

/// <summary>
///授课的教师
/// </summary>
public Teacher Teacher
{
get => _teacher;
set => _teacher = value;
}

/// <summary>
///授课的班级
/// </summary>
public Class Class
{
get => _class;
set => _class = value;
}

/// <summary>
///授课的教师ID
/// </summary>
public int TeacherId => _teacherId;

/// <summary>
///授课的班级Id
/// </summary>
public int ClassId => _classId;
}

模型配置

 /// <summary>
///显示关联配置
/// </summary>
public class ExplicitlyConfiguration : 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 teachingAssociation = modelBuilder.Association<Teaching>();
//配置一个反持久化构造函数
teachingAssociation.HasConstructor(typeof(Teaching).GetConstructor(
BindingFlags.Instance | BindingFlags.NonPublic,
null, new[] { typeof(int), typeof(int) }, null))
//指示TeacherId ClassId已经在此构造函数内赋值 此处需要与反持久化构造函数参数顺序一致
.Map(p => p.TeacherId).Map(p => p.ClassId).End();
//配置关联端 班级关联端为Class这个属性 在关联表中Class的主键ClassId映射为ClassId
teachingAssociation.AssociationEnd(p => p.Class).HasMapping("ClassId", "ClassId");
//配置关联端 教师关联端为Teacher这个属性 在关联表中Teacher的主键TeacherId映射为TeacherId
teachingAssociation.AssociationEnd(p => p.Teacher).HasMapping("TeacherId", "TeacherId");

//配置班级实体型中的关联引用 左端就是关联型上自己类型的这一端 即Class 右端即为另外一端Teacher
classEntity.AssociationReference(p => p.Teachings).HasLeftEnd("Class").HasRightEnd("Teacher");
//配置教师实体型中的关联引用 左端就是关联型上自己类型的这一端 即Teacher 右端即为另外一端Class
teacherEntity.AssociationReference(p => p.Teachings).HasLeftEnd("Teacher").HasRightEnd("Class");
}
}