Lazy Loading 已经有空了。有两种选择:
- 使用 EF Core 生成的代理对象自动加载相关实体或
- 将
ILazyLoader服务与POCO一起使用,在请求时加载相关实体
代理
要使用代理,必须先配置 DbContext:
.AddDbContext<BloggingContext>(
b => b.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString));
之后,任何需要延迟加载的属性都必须设置为virtual:
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public virtual Blog Blog { get; set; }
}
在运行时,EF 将返回继承自实体类的代理对象,并在首次请求时重载惰性属性以加载相关对象。
ILazyLoader 服务
另一个不需要继承的选项是使用 POCO 和 ILazyLoader 服务在需要时加载实体:
public class Blog
{
private ICollection<Post> _posts;
public Blog()
{
}
private Blog(ILazyLoader lazyLoader)
{
LazyLoader = lazyLoader;
}
private ILazyLoader LazyLoader { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Post> Posts
{
get => LazyLoader.Load(this, ref _posts);
set => _posts = value;
}
}
这会添加对 ILazyLoader 接口本身的依赖,这又会在域或业务模型中添加对 EF Core 的依赖。
这可以通过将加载程序作为拉姆达,以及一些约定的魔法:
public class Blog
{
private ICollection<Post> _posts;
public Blog()
{
}
private Blog(Action<object, string> lazyLoader)
{
LazyLoader = lazyLoader;
}
private Action<object, string> LazyLoader { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Post> Posts
{
get => LazyLoader.Load(this, ref _posts);
set => _posts = value;
}
}
这与实际使用属性名称调用加载程序并设置其支持字段的扩展方法结合使用:
public static class PocoLoadingExtensions
{
public static TRelated Load<TRelated>(
this Action<object, string> loader,
object entity,
ref TRelated navigationField,
[CallerMemberName] string navigationName = null)
where TRelated : class
{
loader?.Invoke(entity, navigationName);
return navigationField;
}
}
正如文档警告的那样:
延迟加载委托的构造函数参数必须称为“lazyLoader”。计划在未来版本中使用与此不同的名称进行配置。