显式自关联
场景
前面已经说明,为了便于领域模型准确而深刻地反映现实世界,持久化框架必须“直接地”支持显式关联。而当这种关联同时又是自关联时,情况会更加复杂。以一个活动现场互动的小程序为例,现场来宾通过参与互动游戏建立朋友关系,这是一个多对多的自关联,通常情况下是隐式关联。但如果从运营角度考量活动主办方需要评估各个游戏的运营效果,这时就需要定义一个显式白关联,用以指明朋友关系是在哪个游戏中建立的,请问这种情况应该如何解决?
解决方案
实体模型
/// <summary>
///宾客的朋友关系
/// </summary>
public class Friend
{
/// <summary>
///朋友
/// </summary>
private Guest _friendGuest;
/// <summary>
///朋友的ID
/// </summary>
private int _friendId;
/// <summary>
///于哪个游戏里遇见的
/// </summary>
private string _meetIn;
/// <summary>
///自己
/// </summary>
private Guest _mySelf;
/// <summary>
///自己的ID
/// </summary>
private int _mySelfId;
/// <summary>
///自己
/// </summary>
public Guest MySelf
{
get => _mySelf;
set => _mySelf = value;
}
/// <summary>
///于哪个游戏里遇见的
/// </summary>
public string MeetIn
{
get => _meetIn;
set => _meetIn = value;
}
/// <summary>
///朋友
/// </summary>
public Guest FriendGuest
{
get => _friendGuest;
set => _friendGuest = value;
}
/// <summary>
///自己的ID
/// </summary>
public int MySelfId
{
get => _mySelfId;
set => _mySelfId = value;
}
/// <summary>
///朋友的ID
/// </summary>
public int FriendId
{
get => _friendId;
set => _friendId = value;
}
}
/// <summary>
///宾客
/// </summary>
public class Guest
{
/// <summary>
///朋友是我的人
/// </summary>
private List<Friend> _friendOfmes;
/// <summary>
///我的朋友
/// </summary>
private List<Friend> _friends;
/// <summary>
///宾客ID
/// </summary>
private int _guestId;
/// <summary>
///宾客姓名
/// </summary>
private string _name;
/// <summary>
///我的朋友
/// </summary>
public List<Friend> MyFriends
{
get => _friends;
set => _friends = value;
}
/// <summary>
///宾客ID
/// </summary>
public int GuestId
{
get => _guestId;
set => _guestId = value;
}
/// <summary>
///宾客姓名
/// </summary>
public string Name
{
get => _name;
set => _name = value;
}
/// <summary>
///朋友是我的人
/// </summary>
public List<Friend> FriendOfmes
{
get => _friendOfmes;
set => _friendOfmes = value;
}
}
模型配置
public class ExplicitlySelfConfiguration : 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 guestEntity = modelBuilder.Entity<Guest>();
//配置主键
guestEntity.HasKeyAttribute(p => p.GuestId);
//显式关联型自关联 就是两端都是同一个类的显式关联型
//为宾客和宾客的朋友关系配置显式关联型
var guestAssGuestAssociation = modelBuilder.Association<Friend>();
//配置关联端 此处为自关联 两端都是Guest 所以只要配置每个端即可 无需根据类型进行判定 MySelf这一端在关联表中Friend的主键GuestIde映射为MySelfId
guestAssGuestAssociation.AssociationEnd(p => p.MySelf).HasMapping("GuestId", "MySelfId");
//配置关联端 此处为自关联 两端都是Guest 所以只要配置每个端即可 无需根据类型进行判定 FriendGuest这一端在关联表中Friend的主键GuestId映射为FriendFriendId
guestAssGuestAssociation.AssociationEnd(p => p.FriendGuest).HasMapping("GuestId", "FriendId");
//配置宾客实体型中的关联引用 此处为我的朋友 所以左端就是关联型上自己的这一端 即MySelf 右端即为另外一端FriendGuest
guestEntity.AssociationReference(p => p.MyFriends).HasLeftEnd("MySelf").HasRightEnd("FriendGuest");
//配置宾客实体型中的关联引用 此处为朋友是我的人 所以左端就是关联型上朋友的这一端 即FriendGuest 右端即为另外一端MySelf
guestEntity.AssociationReference(p => p.FriendOfmes).HasLeftEnd("FriendGuest").HasRightEnd("MySelf");
}
}