ABP 如何写仓储

仓储接口

  • 要在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 选项,在需要的时候加载实体的所有详细信息
  • 尽量不要为了取实体的部分属性而为实体创建投影类,而是直接使用聚合根,除非聚合根对性能影响很大.
posted @ 2020-08-19 08:59  Pelva  阅读(288)  评论(0)    收藏  举报