Skip to main content

延迟加载多点触发

场景

延迟加载是指,对象反持久化时不加载它所引用的对象,在需要使用时再加载。这种方式可以提升反持久化性能、减少对数据库的查询量。以Car这个类为例,它聚合Wheel,因此有一个指向后者的引用。从数抓库查询Car的实例时,可以不加载这个引用,等到调用方调用属性Wheels时再行加载。实践中可能存在这样的场景: 一个引用会被类的多个行为使用。仍然以Car为例,对Wheel的引用,除了属性Wheels会用到,ReplaceWheel方法也会用到。在这种场景下,我们需要对象的两个或多个行为都能触发引用加载,即实现延迟加载的多点触发,如何才能实现这种效果呢?

image-20231031201724862

解决方案

实体模型

 /// <summary>
///汽车
/// </summary>
public class Car
{
/// <summary>
///编号
/// </summary>
private string _carCode;

/// <summary>
///名称
/// </summary>
private string _carName;

/// <summary>
///汽车的车轮
/// </summary>
private List<Wheel> _carWheels;

/// <summary>
///编号
/// </summary>
public string CarCode
{
get => _carCode;
set => _carCode = value;
}

/// <summary>
///名称
/// </summary>
public string CarName
{
get => _carName;
set => _carName = value;
}

/// <summary>
///汽车的车轮
/// </summary>
public virtual List<Wheel> CarWheels
{
get => _carWheels;
set => _carWheels = value;
}

/// <summary>
///换轮胎
/// </summary>
/// <param name="oldWheel">旧轮胎</param>
/// <param name="newWheel">新轮胎</param>
public void ReplaceWheel(Wheel oldWheel, Wheel newWheel)
{
CarWheels.RemoveAll(p => p.WheelCode == oldWheel.WheelCode);
CarWheels.Add(newWheel);
}
}
 /// <summary>
///表示车轮
/// </summary>
public class Wheel
{
/// <summary>
///所属车编号
/// </summary>
private string _carCode;

/// <summary>
///车轮编号
/// </summary>
private string _wheelCode;

/// <summary>
///车轮编号
/// </summary>
public string WheelCode
{
get => _wheelCode;
set => _wheelCode = value;
}

/// <summary>
///所属车编号
/// </summary>
public string CarCode
{
get => _carCode;
set => _carCode = value;
}
}

模型配置

 public class LazyLoadingConfiguration : 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 carEntity = modelBuilder.Entity<Car>();
//配置主键
carEntity.HasKeyAttribute(p => p.CarCode).HasKeyIsSelfIncreased(false);

//配置车轮实体型
var wheelEntity = modelBuilder.Entity<Wheel>();
//配置主键
wheelEntity.HasKeyAttribute(p => p.WheelCode).HasKeyIsSelfIncreased(false);

//延迟加载只需要在关联引用上配置HasEnableLazyLoading
//配置隐式关联型
var carAssWheel = modelBuilder.Association<Car, Wheel>();
//配置关联端 End1为Car 在关联表中Car的主键CarCode映射为CarCode
carAssWheel.AssociationEnd(p => p.End1).HasMapping("CarCode", "CarCode");
//配置关联端 End2为Wheel 在关联表中Wheel的主键WheelCode映射为WheelCode
carAssWheel.AssociationEnd(p => p.End2).HasMapping("WheelCode", "WheelCode");
//没有独立映射表 和 Wheel存储在一起
carAssWheel.ToTable("Wheel");

//配置汽车实体型中的关联引用 左端就是关联型上自己类型的这一端 即End1 右端即为另外一端End2
//此处启用了延迟加载 且CarWheels属性定义为virtual
//所有调用此属性访问器的的方法都会触发延迟加载 如ReplaceWheel方法中就访问了CarWheels
//当然 值得注意的是延迟加载会带来性能的下降 如查询一个分页的Car对象后再用延迟加载获取Wheels 10个对象就会访问10次数据库来进行延迟加载
carEntity.AssociationReference(p => p.CarWheels).HasLeftEnd("End1").HasRightEnd("End2")
.HasEnableLazyLoading(true);
}
}