我使用实体框架编写 Web API。 我有两个表,一个用户表和一个地址表。他们有多对多的关系
我希望能够检索所有用户及其地址,如果他们没有,则只有一个空列表。
// Users
public class UserEntity
{
public int UserId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Email { get; set; }
public int PhoneNumber { get; set; }
public string Password { get; set; }
public string PasswordSalt { get; set; }
public string PasswordHash { get; set; }
public string Role { get; set; }
public bool IsActive { get; set; }
public List<UserAdressEntity> Addresses { get; set; }
public List<OrderEntity> Orders { get; set; }
}
// Adress
public class AdressEntity
{
public int AdressId { get; set; }
public int Number { get; set; }
public string CityName { get; set; }
public string Street { get; set; }
public string Country { get; set; }
public List<UserAdressEntity> Users { get; set; }
}
// UserAdress
public class UserAdressEntity
{
public int UserId { get; set; }
public UserEntity User { get; set; }
public int AdressId { get; set; }
public AdressEntity Adress { get; set; }
}
这里我从上下文中检索我的数据
public async Task<IEnumerable<UserEntity>> GetAllWithAdresses()
{
return await _context.Users.ToListAsync();
}
这是我的服务
public async Task<IEnumerable<UserAdressesModel>> GetAllWithAdresses()
{
IEnumerable<UserAdressesModel> result = await _userRepository.GetAllWithAdresses().ContinueWith(u => u.Result.Select(r => r.ToUserAdresses()));
return result;
}
最后是我的地图制作者
internal static UserAdressesModel ToUserAdresses(this UserEntity entity)
{
return new UserAdressesModel()
{
user = entity.ToUserModel(),
Addresses = entity.Addresses != null
? entity.Addresses.Where(ua => ua.Adress is not null)
.Select(ua => ua.Adress.ToAdressModel()).ToList()
: new List<AdressModel>()
};
}
此后,我得到了我的用户,但没有得到关联的地址。 有人可以帮助我吗,非常感谢。
在网上进行一些搜索,多次尝试等等。 使用加入、GroupJoin。
您的“GetAllWithAdresses”缺少该方法的“WithAddresses”方面。你会想要:
return await _context.Users
.Include(x => x.Addresses) // UserAddresses
.ThenInclude(x => x.Address) // UserAddress.Address
.ToListAsync();
但是,请注意,此方法正在加载所有用户及其相关地址详细信息。您可能只想加载用户的摘要表示,然后显示其地址的详细信息。在这种情况下,您将需要 GetUserWithAddress:
public async Task<UserEntity> GetWithAdresses(in userId)
{
return await _context.Users
.Include(x => x.Addresses) // UserAddresses
.ThenInclude(x => x.Address) // UserAddress.Address
.SingleAsync(x => x.UserId == userId);
}
在这种情况下,您只需要传递选定的用户 ID,而不是整个实体(无论如何都不会包含地址详细信息),服务器可以通过 ID 获取。简单地传递实体可能很诱人,但它们通常不完整,并且在断开连接的状态下可能会过时。通过 PK 从数据库中获取单个实体和任何相关详细信息大约是您可以获得的最快操作,并确保您正在查看当前数据状态。
这种方法有点像兔子洞。您每次都需要添加显式方法或参数,以支持不需要相关实体的情况与确实需要一个或多个相关实体的情况。在映射到视图模型等方面,这种方法也不是很有效,因为这会加载视图模型可能只关心一个子集的所有数据。各种现有的映射器库(例如 Mapperly 和 Automapper)支持直接与 EF 的
IQueryable
实现配合使用,并且可以构建高效的查询来针对数据库执行,从而完全避免急切加载相关数据 /w Include
。