通用存储库模式 - DDD 实现

Sun*_*lUK 2 c# domain-driven-design unit-of-work repository-pattern

我目前正在尝试实现一个简单的博客应用程序以用于学习目的。它在 DDD 架构内。
我关心的是如何实现通用存储库模式。
你们能否就我是否正确实施存储库提出您的想法。
这是我第一次使用通用存储库,看起来我根本没有使用它。
下面显示了我的用户存储库的实现。
非常感谢

public interface IRepository<TEntity> where TEntity : class
{
    TEntity GetById(int id);
    IEnumerable<TEntity> GetAll();
    IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);
    void Add(TEntity entity);
    void Update(TEntity entity);
    void Remove(TEntity entity);
}

//Implementation of Generic Repo

using BA.Infrastructure.Data.Context;
using BA.Infrastructure.Data.Interfaces.Helpers;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;

namespace BA.Infrastructure.Data.Repositories.Helpers
{
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        protected readonly BlogDbContext _context;

        public Repository(BlogDbContext context)
        {
            _context = context;
        }

        public TEntity GetById(int id)
        {
            return _context.Set<TEntity>().Find(id);
        }

        public IEnumerable<TEntity> GetAll()
        {
            return _context.Set<TEntity>().ToList();
        }

        public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
        {
            return _context.Set<TEntity>().Where(predicate);
        }

        public void Add(TEntity entity)
        {
            _context.Set<TEntity>().Add(entity);
        }

        public void Update(TEntity entity)
        {
            _context.Entry(entity).State = EntityState.Modified;
        }

        public void Remove(TEntity entity)
        {
            _context.Set<TEntity>().Remove(entity);
        }
    }
}

//unit of work/implementation

using System;

namespace BA.Infrastructure.Data.Interfaces.Helpers
{
    public interface IUnitOfWork : IDisposable
    {
        IBlogRepository Blogs { get; }
        ICategoryRepository Categories { get; }
        ICommentRepository Comments { get; }
        IUserRepository Users { get; }
        void Complete();
    }
}

using BA.Infrastructure.Data.Context;
using BA.Infrastructure.Data.Interfaces;
using BA.Infrastructure.Data.Interfaces.Helpers;

namespace BA.Infrastructure.Data.Repositories.Helpers
{
    //use unit of work within my service. 
    public class UnitOfWork : IUnitOfWork
    {
        private readonly BlogDbContext _context;

        public IBlogRepository Blogs { get; }
        public ICategoryRepository Categories { get; }
        public ICommentRepository Comments { get; }
        public IUserRepository Users { get; }


        public UnitOfWork(BlogDbContext context)
        {
            _context = context;
            Blogs = new BlogRepository(_context);
            Categories = new CategoryRepository(_context);
            Comments = new CommentRepository(_context);
            Users = new UserRepository(_context);
        }

        public void Complete()
        {
            _context.SaveChanges();
        }

        public void Dispose()
        {
            _context.Dispose();
        }
    }
}

//IUser Repository
using BA.Domains;
using BA.Infrastructure.Data.Interfaces.Helpers;

namespace BA.Infrastructure.Data.Interfaces
{
    public interface IUserRepository : IRepository<User>
    {
        User GetUser(int userId);
        void AddUser(User user);
        void UpdateUser(User user);
    }
}

//User Repository
using BA.Domains;
using BA.Infrastructure.Data.Context;
using BA.Infrastructure.Data.Interfaces;
using BA.Infrastructure.Data.Repositories.Helpers;
using System.Data.Entity;
using System.Linq;

namespace BA.Infrastructure.Data.Repositories
{
    public class UserRepository : Repository<User>, IUserRepository
    {
        public UserRepository(BlogDbContext context)
            : base(context)
        {
        }

        public User GetUser(int userId)
        {
            return _context.Users.FirstOrDefault(x => x.Id == userId);
        }

        public void AddUser(User user)
        {
            _context.Users.Add(user);
        }

        public void UpdateUser(User user)
        {
            _context.Entry(user).State = EntityState.Modified;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Voi*_*son 5

你们能否就我是否正确实施存储库提出您的想法。

正如评论中所指出的,您可能不想在那个地方实现存储库。

在 DDD 中,存储库抽象代表了域模型如何理解实体存储与您的管道如何理解实体存储之间的接缝。

格雷格·杨在 2009年写道

存储库模式最初的意图究竟是什么?回顾 [DDD, Evans] 会发现,它是将一系列对象表示为内存中的一个集合,这样域就可以摆脱持久性问题。换句话说,目标是将集合语义放在持久化的对象上......

简单地说,Repository 的契约代表了域对存储库支持的聚合根的持久化机制的契约。

主要思想是存储库应该适合用途。合约传达当前用例所需的数据,底层管道提供它。

Jimmy Bogard 使用了术语“角色特定存储库”

再次格雷格:

这里的答案是仍然使用通用存储库,但使用组合而不是继承,而不是将其作为合同公开给域。

更一般地说:存储库受依赖倒置原则的约束。域代码定义了它需要提供的接口,您的实现找出了最好的方法,您的组合根将两者连接在一起。

因此,对于您的具体示例,合同应如下所示:

public interface IUserRepository
{
    User GetUser(int userId);
    void AddUser(User user);
    void UpdateUser(User user);
}
Run Code Online (Sandbox Code Playgroud)

请注意,我们不共享公共存储库接口,因为这不是模型需要的东西。

使用通用存储库的实现可能看起来像

public class UserRepository : IUserRepository
{
    Repository<User> genericRepo;

    public UserRepository(Repository<User> genericRepo)
    {
        this.genericRepo = genericRepo;
    }

    public User GetUser(int userId)
    {
        return genericRepo.getById(userId);
    }

    // ...
 }
Run Code Online (Sandbox Code Playgroud)

当然,提供一个直接连接到 DBContext 的实现同样是正确的

public class UserRepository : IUserRepository
{
    BlogDbContext context;

    public UserRepository(BlogDbContext context)
    {
        this.context = context;
    }

    public User GetUser(int userId)
    {
        return _context.Users.FirstOrDefault(x => x.Id == userId);
    }

    // ...
 }
Run Code Online (Sandbox Code Playgroud)

合约和实现的分离在支持模型中不同类型的查询时变得有用。

请注意,两种情况下的基本形状是相同的:我们有一个定义契约的接口,一个满足其他契约的实现,以及中间的瘦适配器