仓储接口
- 要在Domain层定义仓储接口
- 每个聚合根定义一个仓储接口,并创建相应实现
- 在Application层中使用仓储时应该注入仓储接口
- 不要在Application层中使用泛型仓储接口(如IRepository<IdentityUser,Guid>
- 不要在Application层 Domain层 中使用IQueryable特性
public class IdentityUser : AggregateRoot<Guid>
{
//...
}
public interface IIdentityUserRepository : IBasicRepository<IdentityUser, Guid>
{
//...
}
- 仓储接口不应继承IRespository<TEntity,Tkey>接口,因为它继承了IQueryable 而仓储不应将IQueryable暴露给应用
- 通常仓储接口继承自IBasicRepository<TEntity,TKey> 或更低级别的接口,如IReadOnlyRepository<TEntity,TKey>
- 不要为实体定义仓储接口,因为它们不是聚合根
仓储方法
- 所有的仓储方法定义为异步
- 仓储的每个方法添加可选参数 cancellationToken 如:
Task<IdentityUser> FindByNormalizedUserNameAsync(
[NotNull] string normalizedUserName,
CancellationToken cancellationToken = default
);
public static class IdentityUserRepositoryExtensions
{
public static IdentityUser FindByNormalizedUserName(
this IIdentityUserRepository repository,
[NotNull] string normalizedUserName)
{
return AsyncHelper.RunSync(
() => repository.FindByNormalizedUserNameAsync(normalizedUserName)
);
}
}
- 为仓储中返回单个实体的方法添加一个可选参数
bool includeDetails=true 例:
Task<IdentityUser> FindByNormalizedUserNameAsync(
[NotNull] string normalizedUserName,
bool includeDetails = true,
CancellationToken cancellationToken = default
);
- 为仓储中返回实体列表的方法添加一个可选参数
bool includeDetails=false 例:
Task<List<IdentityUser>> GetListByNormalizedRoleNameAsync(
string normalizedRoleName,
bool includeDetails = false,
CancellationToken cancellationToken = default
);
- 不要创建复合类,并通过仓储方法返回组合实体,如 UserWithRoles UserWithTokens UserWithRolesAndTokens, 而是使用includeDetails 选项,在需要的时候加载实体的所有详细信息
- 尽量不要为了取实体的部分属性而为实体创建投影类,而是直接使用聚合根,除非聚合根对性能影响很大.