仓储(Repository)

Respository模式在示例中的实际目的小结一下

Repository与Dal的区别

Repository是DDD中的概念,强调Repository是受Domain驱动的,Repository中定义的功能要体现Domain的意图和约束,而Dal更纯粹的就是提 供数据访问的功能,并不严格受限于Business层。

使用Repository,隐含着一种意图倾向,就是 Domain需要什么我才提供什么,不该提供的功能就不要提供,一切都是以Domain的需求为核心;而使用Dal,其意图倾向在于我Dal层能使用的数 据库访问操作提供给Business层,你Business要用哪个自己选。换一个Business也可以用我这个Dal,一切是以我Dal能提供什么操 作为核心。

LCL与Repository

Default Repositories

在LCL中,一个存储库类实现了IRepository<TEntity,TPrimaryKey> 您需要手工注入 IRepository<TEntity> (IRepository<TEntity, TPrimaryKey>)。 一个示例应用程序服务使用一个存储库来将一个实体插入到数据库:

public class RoleAppService : IRoleAppService
{
    private readonly IRepository<Role> _roleRepository;
    public RoleAppService(IRepository<Role> roleRepository)
    {
        _roleRepository = roleRepository;
    }
    public void CreateRole(Role input)
    {        
        _roleRepository.Insert(input);
    }
}

RoleAppService 注入IRepository<Role> ,并使用插入方法。

自定义库

当您需要为该实体创建一个自定义存储库方法时,您只需要为实体创建一个存储库类。

一个Role实体的存储库定义如下所示:

public interface IRoleRepository : IRepository<Role> 
{  
}  

IRoleRepository延伸 IRepository<TEntity>。它用于定义具有主键类型的Guid类型的实体。 如果您的实体的主键不是Guid,您可以扩展IRepository<TEntity,TPrimaryKey>:接口如下所示:

public interface IRoleRepository : IRepository<Role, long>
{
}

提示: Role

Role是实体类,请查看实体类的编写。

自定义库的实现

LCL的设计目的是独立于特定的ORM(对象/关系映射)框架或其他访问数据库的技术。存储库是在NHibernate,MongoDB和EntityFramework中实现的,它是开箱即用的。查看文档以实现在LCL中的存储库。

基础库的方法

public interface IRepository<TAggregateRoot>  where TAggregateRoot : class, IAggregateRoot
{
        IRepositoryContext Context { get; }
        void Add(TAggregateRoot aggregateRoot);
        TAggregateRoot GetByKey(object key);
        IQueryable<TAggregateRoot> FindAll();
        IQueryable<TAggregateRoot> FindAll(Expression<func<TAggregateRoot, dynamic=dynamic >> sortPredicate, SortOrder sortOrder);
        PagedResult<TAggregateRoot> FindAll(Expression<func<TAggregateRoot, dynamic=dynamic >> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize);
        IQueryable<TAggregateRoot> FindAll(ISpecification<TAggregateRoot> specification);
        IQueryable<TAggregateRoot> FindAll(ISpecification<TAggregateRoot> specification, Expression<func<TAggregateRoot, dynamic=dynamic >> sortPredicate, SortOrder sortOrder);
        PagedResult<TAggregateRoot> FindAll(ISpecification<TAggregateRoot> specification, Expression<func<TAggregateRoot, dynamic=dynamic >> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize);
        IQueryable<TAggregateRoot> FindAll(params Expression<func<TAggregateRoot, dynamic=dynamic >>[] eagerLoadingProperties);
        IQueryable<TAggregateRoot> FindAll(Expression<func<TAggregateRoot, dynamic=dynamic >> sortPredicate, SortOrder sortOrder, params Expression<func<TAggregateRoot, dynamic=dynamic >>[] eagerLoadingProperties);
        PagedResult<TAggregateRoot> FindAll(Expression<func<TAggregateRoot, dynamic=dynamic >> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize, params Expression<func<TAggregateRoot, dynamic=dynamic >>[] eagerLoadingProperties);
        IQueryable<TAggregateRoot> FindAll(ISpecification<TAggregateRoot> specification, params Expression<func<TAggregateRoot, dynamic=dynamic >>[] eagerLoadingProperties);
        IQueryable<TAggregateRoot> FindAll(ISpecification<TAggregateRoot> specification, Expression<func<TAggregateRoot, dynamic=dynamic >> sortPredicate, SortOrder sortOrder, params Expression<func<TAggregateRoot, dynamic=dynamic >>[] eagerLoadingProperties);
        PagedResult<TAggregateRoot> FindAll(ISpecification<TAggregateRoot> specification, Expression<func<TAggregateRoot, dynamic=dynamic >> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize, params Expression<func<TAggregateRoot, dynamic=dynamic >>[] eagerLoadingProperties);
        TAggregateRoot Find(ISpecification<TAggregateRoot> specification);
        TAggregateRoot Find(ISpecification<TAggregateRoot> specification, params Expression<func<TAggregateRoot, dynamic=dynamic >>[] eagerLoadingProperties);
        bool Exists(ISpecification<TAggregateRoot> specification);
        void Remove(TAggregateRoot aggregateRoot);
 
        void Update(TAggregateRoot aggregateRoot);
}

Get方法用于获得给定主键(Id)的实体。如果数据库中没有给定Id的实体,它会抛出异常。单个方法与Get相似,但使用表达式而不是Id。因此,您可以编写一个lambda表达式来获得一个实体。示例用法:

var role = _roleRepository.GetByKey(42);
var role = _roleRepository.Find(p => p.Name == "John");

注意,如果没有给定条件的实体,或者存在多个实体,那么单一方法会抛出异常。

FirstOrDefault是类似的,但是如果没有给定的Id或表达式的实体,则返回null(而不是抛出异常)。如果给定条件下有多个实体,则返回第一个实体。

FindAll返回这个IQueryable < T >。所以,你可以在它之后添加Linq的方法。例子:

//Example 1
var query = from role in _roleRepository.FindAll()
            where role.IsActive
            orderby role.Name
            select role;
var role = query.ToList();
//Example 2:
List<Role> roleList2 = _personRepository.FindAll().Where(p => p.Name.Contains("H")).OrderBy(p => p.Name).Skip(40).Take(20).ToList();

使用FindAll,几乎所有的查询都可以在Linq写。甚至可以在连接表达式中使用它。

About IQueryable<T>

当您从存储库方法中调用FindAll()时,必须有一个开放的数据库连接。这是因为IQueryable的延迟执行。 它不执行数据库查询,除非您调用ToList()方法,或者在foreach循环中使用IQueryable(或以某种方式访问查询的项)。 因此,当您调用ToList()方法时,数据库连接必须是活着的。 对于一个web应用程序,在大多数情况下,您并不关心这一点,因为MVC控制器方法是默认的工作单元, 并且数据库连接可以用于整个请求。请参阅UnitOfWork文档以更好地理解它。

库的最佳实践