我正在研究延迟加载。我不明白延迟加载是如何工作的,我应该做些什么来改变它吗?
这是我的第一个案例:
我有用户、用户角色和角色类。用户与角色具有多对多的关系。所以我创建用户角色类来处理关系。用户不包括所有情况的角色。 (不要介意 UserRole 中的 Id )
public class User : IUser
{
public bool IsActive { get; set; }
public int Id { get; private set; }
public string Email { get; set; }
public byte[] PasswordHash { get; set; }
public byte[] PasswordSalt { get; set; }
public string? Phone { get; set; }
public List<UserRole> UserRoles { get; set; }
}
public class UserRole : IEntity
{
public int Id { get; private set; }
[ForeignKey(nameof(User))]
public int UserId { get; set; }
public User User { get; set; }
[ForeignKey(nameof(Role))]
public int RoleId { get; set; }
public Role Role { get; set; }
}
public class Role : IEntity
{
public int Id { get; private set; }
public string Name { get; set; }
}
这是我的第二个案例:
我有与用户相关的文章类。在这种情况下,文章使用 Creator.Email ( User ) 或创建者名称,这意味着使用文章的任何查询都包含用户。
public class Article : IEntity
{
public Article() => CreatedAt = DateTime.Now;
public bool IsDeleted { get; set; }
public int Id { get; private set; }
public string Title { get; set; } = "Başlık";
public string Content { get; set; } = "İçerik";
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
[ForeignKey(nameof(User))] public int CreatorId { get; set; }
[ForeignKey(nameof(User))] public int? DeletedBy { get; set; }
public User? Creator { get; set; }
public List<ArticleCategory> ArticleCategories { get; set; }
}
所以我的问题是我应该为延迟加载这些相关属性做些什么吗?
如果是,我应该做什么,如果不是,它如何与 efcore 一起使用?
对于用户示例,它是从数据库获取数据并保留在内存中直到被请求,还是不会进入 UserRoles 和 Roles 表直到被请求?
如果两者都不是,它实际上是如何工作的?
这里是我如何以简单的方式从数据库获取所有数据的示例。
var users = context.Users
.Include(u => u.UserRoles)
.ThenInclude(ur => ur.Role);
在某些情况下,即使我不请求用户的角色,它们是否会从数据库中获取,如果是,它们是否会保留在内存中?
Lazy<T>
是一个框架提供的类,用于支持任何自定义开发人员定义的逻辑/函数的延迟初始化(通常用于多线程环境,但不限于此)。与 EF Core 无关。
另一方面,EF Core 中数据的延迟加载是在不使用
Lazy
的情况下完成的(至少在面向用户的 API/约定中)。 EF 中有两种主要的延迟加载“风格” - with proxy 和 without。第一种方法依赖于使用特殊的包,并且需要相应的属性是虚拟的:
public class Blog
{
// ...
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
// ...
public virtual Blog Blog { get; set; }
}
这会生成特殊的代理类,除非需要(即以某种方式访问),否则它将推迟相关数据的加载。例如:
var post = _context.Posts.First(); // the Blog will not be loaded
// ...
var postBlog = post.Blog; // here the lazy loading will happen.
这两个概念相关,但仍然有些不同。
附注
需要注意的一件事 - EF DbContext 不是线程安全的(即一次只能由一个线程使用,并且不支持通过同一实例对数据库进行并行查询),这消除了一部分问题,通过以下方式解决
Lazy
。
我个人建议谨慎使用延迟加载,因为它可能导致臭名昭著的 N+1 问题 - 请检查文档的注意延迟加载部分。