Skip to main content

隐式关联的独立映射

场景

20231031200046856

让我们来看一个多对多关联的例子。一个老师负责教授多个班级,一个班级有多个老师 (每个科目一个老师)。这是一个典型的多对多关联,请大家思考一下,在关系型数据库中应该怎么存储? 通常情况下,我们需要一个关联表,通常会取名Teaching。 那么,是不是应该相应定义一个Teaching类,然后让Teacher和Class分别与它建立关联呢?仿佛只有这样才能顺利使用ORM框架才能完成持久化的任务。这个Teaching类不是为了表达业务领域的现实,而纯粹是为了实现存储需要而定义的,称为"存储类"。它的存在是违背面向对象和领域驱动设计原则的。 特别是对于自关联(如参加活动的宾客通过互动游戏建立的朋友关系,就是一个多对多的自关联)来说,会显得更加别扭。明明是宾客自身的关联,现在变成了在宾客与""存储类"之间建立两个关联,模型已经完全悖离了现实 需要特别指出,一对多场景下也有可能遇到上述问题,例如模型需要在现有数据库上运行,而现有数据库出于特殊原因对一对多关联使用了关联表有什么办法避免定义存储类吗?

解决方案

实体模型

/// <summary>
/// 教师
/// </summary>
public class Teacher
{
/// <summary>
/// 年龄
/// </summary>
private int _age;

/// <summary>
/// 教授班级
/// </summary>
private List<Class> _classes;

/// <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 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<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 class IndependentImplicitConfiguration : 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);

//隐式关联也可以独立映射 需要配置ToTable
//配置教师与班级间的关联型
var classTeacherAssociation = modelBuilder.Association<Class, Teacher>();
//配置关联端 End1为Class 在关联表中Class的主键ClassId映射为ClassId
classTeacherAssociation.AssociationEnd(p => p.End1).HasMapping("ClassId", "ClassId");
//配置关联端 End2为Teacher 在关联表中Teacher的主键TeacherId映射为TeacherId
classTeacherAssociation.AssociationEnd(p => p.End2).HasMapping("TeacherId", "TeacherId");
//多对多 独立映射表
classTeacherAssociation.ToTable("Teaching");

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