znlgis 博客

GIS开发与技术分享

第十四章:仓储模式与依赖注入

目录


14.1 仓储模式概述

14.1.1 什么是仓储模式

仓储模式(Repository Pattern)是一种数据访问模式,它在数据访问层和业务逻辑层之间建立一个抽象层。

核心概念

// 传统方式:业务逻辑直接依赖数据库操作
public class StudentService
{
    private SqlSugarClient _db;
    
    public List<Student> GetStudents()
    {
        return _db.Queryable<Student>().ToList(); // 直接依赖SqlSugar
    }
}

// 仓储模式:业务逻辑依赖仓储接口
public class StudentService
{
    private IStudentRepository _repository;
    
    public List<Student> GetStudents()
    {
        return _repository.GetAll(); // 依赖抽象接口
    }
}

14.1.2 仓储模式的优势

  1. 解耦:业务逻辑与数据访问分离
  2. 可测试:便于单元测试(Mock)
  3. 可维护:集中管理数据访问逻辑
  4. 可复用:避免重复代码
  5. 灵活性:易于更换数据访问技术

14.2 基础仓储实现

14.2.1 定义仓储接口

// 基础仓储接口
public interface IRepository<T> where T : class, new()
{
    // 查询
    T GetById(object id);
    List<T> GetList();
    List<T> GetList(Expression<Func<T, bool>> whereExpression);
    
    // 分页
    PageResult<T> GetPageList(int pageIndex, int pageSize);
    PageResult<T> GetPageList(Expression<Func<T, bool>> whereExpression, int pageIndex, int pageSize);
    
    // 插入
    int Insert(T entity);
    int InsertRange(List<T> entities);
    
    // 更新
    bool Update(T entity);
    bool Update(Expression<Func<T, T>> columns, Expression<Func<T, bool>> whereExpression);
    
    // 删除
    bool Delete(T entity);
    bool Delete(object id);
    bool Delete(Expression<Func<T, bool>> whereExpression);
    
    // 聚合
    int Count(Expression<Func<T, bool>> whereExpression);
    bool Any(Expression<Func<T, bool>> whereExpression);
    
    // 事务
    void BeginTran();
    void CommitTran();
    void RollbackTran();
}

// 学生仓储接口(特定实体)
public interface IStudentRepository : IRepository<Student>
{
    // 特定业务方法
    List<Student> GetStudentsByClass(int classId);
    List<Student> GetStudentsByAge(int minAge, int maxAge);
    Student GetStudentByEmail(string email);
}

14.2.2 实现基础仓储

// 基础仓储实现
public class Repository<T> : IRepository<T> where T : class, new()
{
    protected readonly ISqlSugarClient _db;
    
    public Repository(ISqlSugarClient db)
    {
        _db = db;
    }
    
    public virtual T GetById(object id)
    {
        return _db.Queryable<T>().InSingle(id);
    }
    
    public virtual List<T> GetList()
    {
        return _db.Queryable<T>().ToList();
    }
    
    public virtual List<T> GetList(Expression<Func<T, bool>> whereExpression)
    {
        return _db.Queryable<T>().Where(whereExpression).ToList();
    }
    
    public virtual PageResult<T> GetPageList(int pageIndex, int pageSize)
    {
        int totalCount = 0;
        var list = _db.Queryable<T>()
            .ToPageList(pageIndex, pageSize, ref totalCount);
        
        return new PageResult<T>
        {
            PageIndex = pageIndex,
            PageSize = pageSize,
            TotalCount = totalCount,
            TotalPages = (int)Math.Ceiling(totalCount / (double)pageSize),
            Items = list
        };
    }
    
    public virtual PageResult<T> GetPageList(
        Expression<Func<T, bool>> whereExpression, 
        int pageIndex, 
        int pageSize)
    {
        int totalCount = 0;
        var list = _db.Queryable<T>()
            .Where(whereExpression)
            .ToPageList(pageIndex, pageSize, ref totalCount);
        
        return new PageResult<T>
        {
            PageIndex = pageIndex,
            PageSize = pageSize,
            TotalCount = totalCount,
            TotalPages = (int)Math.Ceiling(totalCount / (double)pageSize),
            Items = list
        };
    }
    
    public virtual int Insert(T entity)
    {
        return _db.Insertable(entity).ExecuteReturnIdentity();
    }
    
    public virtual int InsertRange(List<T> entities)
    {
        return _db.Insertable(entities).ExecuteCommand();
    }
    
    public virtual bool Update(T entity)
    {
        return _db.Updateable(entity).ExecuteCommandHasChange();
    }
    
    public virtual bool Update(
        Expression<Func<T, T>> columns, 
        Expression<Func<T, bool>> whereExpression)
    {
        return _db.Updateable<T>()
            .SetColumns(columns)
            .Where(whereExpression)
            .ExecuteCommandHasChange();
    }
    
    public virtual bool Delete(T entity)
    {
        return _db.Deleteable(entity).ExecuteCommandHasChange();
    }
    
    public virtual bool Delete(object id)
    {
        return _db.Deleteable<T>().In(id).ExecuteCommandHasChange();
    }
    
    public virtual bool Delete(Expression<Func<T, bool>> whereExpression)
    {
        return _db.Deleteable<T>()
            .Where(whereExpression)
            .ExecuteCommandHasChange();
    }
    
    public virtual int Count(Expression<Func<T, bool>> whereExpression)
    {
        return _db.Queryable<T>().Where(whereExpression).Count();
    }
    
    public virtual bool Any(Expression<Func<T, bool>> whereExpression)
    {
        return _db.Queryable<T>().Where(whereExpression).Any();
    }
    
    public virtual void BeginTran()
    {
        _db.BeginTran();
    }
    
    public virtual void CommitTran()
    {
        _db.CommitTran();
    }
    
    public virtual void RollbackTran()
    {
        _db.RollbackTran();
    }
}

// 学生仓储实现
public class StudentRepository : Repository<Student>, IStudentRepository
{
    public StudentRepository(ISqlSugarClient db) : base(db)
    {
    }
    
    public List<Student> GetStudentsByClass(int classId)
    {
        return _db.Queryable<Student>()
            .Where(s => s.ClassId == classId)
            .ToList();
    }
    
    public List<Student> GetStudentsByAge(int minAge, int maxAge)
    {
        return _db.Queryable<Student>()
            .Where(s => s.Age >= minAge && s.Age <= maxAge)
            .ToList();
    }
    
    public Student GetStudentByEmail(string email)
    {
        return _db.Queryable<Student>()
            .First(s => s.Email == email);
    }
}

14.3 泛型仓储

增强的泛型仓储实现:

// 异步仓储接口
public interface IRepositoryAsync<T> where T : class, new()
{
    Task<T> GetByIdAsync(object id);
    Task<List<T>> GetListAsync();
    Task<List<T>> GetListAsync(Expression<Func<T, bool>> whereExpression);
    Task<PageResult<T>> GetPageListAsync(int pageIndex, int pageSize);
    Task<int> InsertAsync(T entity);
    Task<int> InsertRangeAsync(List<T> entities);
    Task<bool> UpdateAsync(T entity);
    Task<bool> DeleteAsync(object id);
    Task<int> CountAsync(Expression<Func<T, bool>> whereExpression);
    Task<bool> AnyAsync(Expression<Func<T, bool>> whereExpression);
}

// 异步仓储实现
public class RepositoryAsync<T> : IRepositoryAsync<T> where T : class, new()
{
    protected readonly ISqlSugarClient _db;
    
    public RepositoryAsync(ISqlSugarClient db)
    {
        _db = db;
    }
    
    public virtual async Task<T> GetByIdAsync(object id)
    {
        return await _db.Queryable<T>().InSingleAsync(id);
    }
    
    public virtual async Task<List<T>> GetListAsync()
    {
        return await _db.Queryable<T>().ToListAsync();
    }
    
    public virtual async Task<List<T>> GetListAsync(Expression<Func<T, bool>> whereExpression)
    {
        return await _db.Queryable<T>().Where(whereExpression).ToListAsync();
    }
    
    public virtual async Task<PageResult<T>> GetPageListAsync(int pageIndex, int pageSize)
    {
        RefAsync<int> totalCount = 0;
        var list = await _db.Queryable<T>()
            .ToPageListAsync(pageIndex, pageSize, totalCount);
        
        return new PageResult<T>
        {
            PageIndex = pageIndex,
            PageSize = pageSize,
            TotalCount = totalCount,
            TotalPages = (int)Math.Ceiling(totalCount / (double)pageSize),
            Items = list
        };
    }
    
    public virtual async Task<int> InsertAsync(T entity)
    {
        return await _db.Insertable(entity).ExecuteReturnIdentityAsync();
    }
    
    public virtual async Task<int> InsertRangeAsync(List<T> entities)
    {
        return await _db.Insertable(entities).ExecuteCommandAsync();
    }
    
    public virtual async Task<bool> UpdateAsync(T entity)
    {
        return await _db.Updateable(entity).ExecuteCommandHasChangeAsync();
    }
    
    public virtual async Task<bool> DeleteAsync(object id)
    {
        return await _db.Deleteable<T>().In(id).ExecuteCommandHasChangeAsync();
    }
    
    public virtual async Task<int> CountAsync(Expression<Func<T, bool>> whereExpression)
    {
        return await _db.Queryable<T>().Where(whereExpression).CountAsync();
    }
    
    public virtual async Task<bool> AnyAsync(Expression<Func<T, bool>> whereExpression)
    {
        return await _db.Queryable<T>().Where(whereExpression).AnyAsync();
    }
}

// 完整功能的泛型仓储
public class FullRepository<T> : RepositoryAsync<T>, IRepository<T>, IRepositoryAsync<T> 
    where T : class, new()
{
    public FullRepository(ISqlSugarClient db) : base(db)
    {
    }
    
    // 实现同步方法
    public T GetById(object id)
    {
        return _db.Queryable<T>().InSingle(id);
    }
    
    public List<T> GetList()
    {
        return _db.Queryable<T>().ToList();
    }
    
    public List<T> GetList(Expression<Func<T, bool>> whereExpression)
    {
        return _db.Queryable<T>().Where(whereExpression).ToList();
    }
    
    public PageResult<T> GetPageList(int pageIndex, int pageSize)
    {
        int totalCount = 0;
        var list = _db.Queryable<T>()
            .ToPageList(pageIndex, pageSize, ref totalCount);
        
        return new PageResult<T>
        {
            PageIndex = pageIndex,
            PageSize = pageSize,
            TotalCount = totalCount,
            Items = list
        };
    }
    
    public PageResult<T> GetPageList(
        Expression<Func<T, bool>> whereExpression,
        int pageIndex,
        int pageSize)
    {
        int totalCount = 0;
        var list = _db.Queryable<T>()
            .Where(whereExpression)
            .ToPageList(pageIndex, pageSize, ref totalCount);
        
        return new PageResult<T>
        {
            PageIndex = pageIndex,
            PageSize = pageSize,
            TotalCount = totalCount,
            Items = list
        };
    }
    
    public int Insert(T entity)
    {
        return _db.Insertable(entity).ExecuteReturnIdentity();
    }
    
    public int InsertRange(List<T> entities)
    {
        return _db.Insertable(entities).ExecuteCommand();
    }
    
    public bool Update(T entity)
    {
        return _db.Updateable(entity).ExecuteCommandHasChange();
    }
    
    public bool Update(
        Expression<Func<T, T>> columns,
        Expression<Func<T, bool>> whereExpression)
    {
        return _db.Updateable<T>()
            .SetColumns(columns)
            .Where(whereExpression)
            .ExecuteCommandHasChange();
    }
    
    public bool Delete(T entity)
    {
        return _db.Deleteable(entity).ExecuteCommandHasChange();
    }
    
    public bool Delete(object id)
    {
        return _db.Deleteable<T>().In(id).ExecuteCommandHasChange();
    }
    
    public bool Delete(Expression<Func<T, bool>> whereExpression)
    {
        return _db.Deleteable<T>()
            .Where(whereExpression)
            .ExecuteCommandHasChange();
    }
    
    public int Count(Expression<Func<T, bool>> whereExpression)
    {
        return _db.Queryable<T>().Where(whereExpression).Count();
    }
    
    public bool Any(Expression<Func<T, bool>> whereExpression)
    {
        return _db.Queryable<T>().Where(whereExpression).Any();
    }
    
    public void BeginTran()
    {
        _db.BeginTran();
    }
    
    public void CommitTran()
    {
        _db.CommitTran();
    }
    
    public void RollbackTran()
    {
        _db.RollbackTran();
    }
}

14.4 工作单元模式

// 工作单元接口
public interface IUnitOfWork : IDisposable
{
    ISqlSugarClient Db { get; }
    
    void BeginTran();
    void CommitTran();
    void RollbackTran();
    
    IRepository<T> GetRepository<T>() where T : class, new();
}

// 工作单元实现
public class UnitOfWork : IUnitOfWork
{
    private readonly ISqlSugarClient _db;
    private readonly Dictionary<Type, object> _repositories;
    private bool _disposed = false;
    
    public UnitOfWork(ISqlSugarClient db)
    {
        _db = db;
        _repositories = new Dictionary<Type, object>();
    }
    
    public ISqlSugarClient Db => _db;
    
    public void BeginTran()
    {
        _db.BeginTran();
    }
    
    public void CommitTran()
    {
        _db.CommitTran();
    }
    
    public void RollbackTran()
    {
        _db.RollbackTran();
    }
    
    public IRepository<T> GetRepository<T>() where T : class, new()
    {
        var type = typeof(T);
        
        if (!_repositories.ContainsKey(type))
        {
            _repositories[type] = new Repository<T>(_db);
        }
        
        return (IRepository<T>)_repositories[type];
    }
    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _repositories.Clear();
            }
            _disposed = true;
        }
    }
}

// 使用工作单元
public class OrderService
{
    private readonly IUnitOfWork _unitOfWork;
    
    public OrderService(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
    
    public bool CreateOrder(Order order, List<OrderItem> items)
    {
        try
        {
            _unitOfWork.BeginTran();
            
            // 创建订单
            var orderRepo = _unitOfWork.GetRepository<Order>();
            var orderId = orderRepo.Insert(order);
            
            // 添加订单项
            var itemRepo = _unitOfWork.GetRepository<OrderItem>();
            foreach (var item in items)
            {
                item.OrderId = orderId;
                itemRepo.Insert(item);
            }
            
            // 更新库存
            var productRepo = _unitOfWork.GetRepository<Product>();
            foreach (var item in items)
            {
                productRepo.Update(
                    p => new Product { Stock = p.Stock - item.Quantity },
                    p => p.Id == item.ProductId);
            }
            
            _unitOfWork.CommitTran();
            return true;
        }
        catch
        {
            _unitOfWork.RollbackTran();
            return false;
        }
    }
}

14.5 依赖注入集成

14.5.1 ASP.NET Core集成

// Startup.cs 或 Program.cs
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 注册SqlSugarClient
        services.AddSingleton<ISqlSugarClient>(provider =>
        {
            return new SqlSugarClient(new ConnectionConfig
            {
                ConnectionString = Configuration.GetConnectionString("DefaultConnection"),
                DbType = DbType.SqlServer,
                IsAutoCloseConnection = true,
                InitKeyType = InitKeyType.Attribute
            });
        });
        
        // 注册仓储
        services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
        services.AddScoped<IStudentRepository, StudentRepository>();
        services.AddScoped<ITeacherRepository, TeacherRepository>();
        
        // 注册工作单元
        services.AddScoped<IUnitOfWork, UnitOfWork>();
        
        // 注册服务
        services.AddScoped<IStudentService, StudentService>();
        services.AddScoped<ITeacherService, TeacherService>();
        
        services.AddControllers();
    }
}

// 使用 SqlSugarScope 支持多租户
public void ConfigureServicesWithScope(IServiceCollection services)
{
    services.AddSingleton<SqlSugarScope>(provider =>
    {
        return new SqlSugarScope(new ConnectionConfig
        {
            ConnectionString = Configuration.GetConnectionString("DefaultConnection"),
            DbType = DbType.SqlServer,
            IsAutoCloseConnection = true
        });
    });
    
    // 注册为ISqlSugarClient
    services.AddScoped<ISqlSugarClient>(provider =>
    {
        return provider.GetRequiredService<SqlSugarScope>();
    });
}

// 控制器中使用
[ApiController]
[Route("api/[controller]")]
public class StudentController : ControllerBase
{
    private readonly IStudentRepository _repository;
    private readonly IStudentService _service;
    
    public StudentController(
        IStudentRepository repository,
        IStudentService service)
    {
        _repository = repository;
        _service = service;
    }
    
    [HttpGet]
    public ActionResult<List<Student>> GetAll()
    {
        var students = _repository.GetList();
        return Ok(students);
    }
    
    [HttpGet("{id}")]
    public ActionResult<Student> Get(int id)
    {
        var student = _repository.GetById(id);
        if (student == null)
            return NotFound();
        
        return Ok(student);
    }
    
    [HttpPost]
    public ActionResult<int> Create([FromBody] Student student)
    {
        var id = _repository.Insert(student);
        return Ok(id);
    }
}

14.5.2 Autofac集成

public class AutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        // 注册SqlSugarClient
        builder.Register(c =>
        {
            return new SqlSugarClient(new ConnectionConfig
            {
                ConnectionString = "Server=.;Database=test;User ID=sa;Password=123;",
                DbType = DbType.SqlServer,
                IsAutoCloseConnection = true
            });
        }).As<ISqlSugarClient>().SingleInstance();
        
        // 注册泛型仓储
        builder.RegisterGeneric(typeof(Repository<>))
            .As(typeof(IRepository<>))
            .InstancePerLifetimeScope();
        
        // 注册具体仓储
        builder.RegisterType<StudentRepository>()
            .As<IStudentRepository>()
            .InstancePerLifetimeScope();
        
        // 注册工作单元
        builder.RegisterType<UnitOfWork>()
            .As<IUnitOfWork>()
            .InstancePerLifetimeScope();
        
        // 自动注册所有服务
        builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
            .Where(t => t.Name.EndsWith("Service"))
            .AsImplementedInterfaces()
            .InstancePerLifetimeScope();
    }
}

// Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        var host = Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureContainer<ContainerBuilder>(builder =>
            {
                builder.RegisterModule<AutofacModule>();
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })
            .Build();
        
        host.Run();
    }
}

14.6 服务层设计

// 服务层接口
public interface IStudentService
{
    StudentDto GetById(int id);
    List<StudentDto> GetAll();
    PageResult<StudentDto> GetPageList(int pageIndex, int pageSize);
    int Create(CreateStudentDto dto);
    bool Update(int id, UpdateStudentDto dto);
    bool Delete(int id);
}

// 服务层实现
public class StudentService : IStudentService
{
    private readonly IStudentRepository _repository;
    private readonly IMapper _mapper;
    private readonly ILogger<StudentService> _logger;
    
    public StudentService(
        IStudentRepository repository,
        IMapper mapper,
        ILogger<StudentService> logger)
    {
        _repository = repository;
        _mapper = mapper;
        _logger = logger;
    }
    
    public StudentDto GetById(int id)
    {
        _logger.LogInformation($"获取学生信息: {id}");
        
        var student = _repository.GetById(id);
        if (student == null)
        {
            throw new NotFoundException($"学生不存在: {id}");
        }
        
        return _mapper.Map<StudentDto>(student);
    }
    
    public List<StudentDto> GetAll()
    {
        var students = _repository.GetList();
        return _mapper.Map<List<StudentDto>>(students);
    }
    
    public PageResult<StudentDto> GetPageList(int pageIndex, int pageSize)
    {
        var result = _repository.GetPageList(pageIndex, pageSize);
        
        return new PageResult<StudentDto>
        {
            PageIndex = result.PageIndex,
            PageSize = result.PageSize,
            TotalCount = result.TotalCount,
            TotalPages = result.TotalPages,
            Items = _mapper.Map<List<StudentDto>>(result.Items)
        };
    }
    
    public int Create(CreateStudentDto dto)
    {
        _logger.LogInformation($"创建学生: {dto.Name}");
        
        // 验证
        if (string.IsNullOrEmpty(dto.Name))
        {
            throw new ValidationException("姓名不能为空");
        }
        
        // 检查邮箱是否已存在
        if (_repository.Any(s => s.Email == dto.Email))
        {
            throw new ValidationException("邮箱已存在");
        }
        
        var student = _mapper.Map<Student>(dto);
        student.CreateTime = DateTime.Now;
        
        return _repository.Insert(student);
    }
    
    public bool Update(int id, UpdateStudentDto dto)
    {
        _logger.LogInformation($"更新学生: {id}");
        
        var student = _repository.GetById(id);
        if (student == null)
        {
            throw new NotFoundException($"学生不存在: {id}");
        }
        
        _mapper.Map(dto, student);
        student.UpdateTime = DateTime.Now;
        
        return _repository.Update(student);
    }
    
    public bool Delete(int id)
    {
        _logger.LogInformation($"删除学生: {id}");
        
        var student = _repository.GetById(id);
        if (student == null)
        {
            throw new NotFoundException($"学生不存在: {id}");
        }
        
        return _repository.Delete(id);
    }
}

// 复杂业务服务
public class OrderService
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IMapper _mapper;
    private readonly ILogger<OrderService> _logger;
    
    public OrderService(
        IUnitOfWork unitOfWork,
        IMapper mapper,
        ILogger<OrderService> logger)
    {
        _unitOfWork = unitOfWork;
        _mapper = mapper;
        _logger = logger;
    }
    
    public int CreateOrder(CreateOrderDto dto)
    {
        _logger.LogInformation($"创建订单: 用户{dto.UserId}");
        
        try
        {
            _unitOfWork.BeginTran();
            
            // 1. 创建订单
            var order = _mapper.Map<Order>(dto);
            order.OrderNo = GenerateOrderNo();
            order.CreateTime = DateTime.Now;
            order.Status = OrderStatus.Pending;
            
            var orderRepo = _unitOfWork.GetRepository<Order>();
            var orderId = orderRepo.Insert(order);
            
            // 2. 创建订单项
            var itemRepo = _unitOfWork.GetRepository<OrderItem>();
            decimal totalAmount = 0;
            
            foreach (var itemDto in dto.Items)
            {
                // 检查库存
                var productRepo = _unitOfWork.GetRepository<Product>();
                var product = productRepo.GetById(itemDto.ProductId);
                
                if (product == null)
                {
                    throw new ValidationException($"商品不存在: {itemDto.ProductId}");
                }
                
                if (product.Stock < itemDto.Quantity)
                {
                    throw new ValidationException($"库存不足: {product.Name}");
                }
                
                // 创建订单项
                var item = new OrderItem
                {
                    OrderId = orderId,
                    ProductId = itemDto.ProductId,
                    ProductName = product.Name,
                    Price = product.Price,
                    Quantity = itemDto.Quantity,
                    Amount = product.Price * itemDto.Quantity
                };
                
                itemRepo.Insert(item);
                totalAmount += item.Amount;
                
                // 减库存
                product.Stock -= itemDto.Quantity;
                productRepo.Update(product);
            }
            
            // 3. 更新订单总金额
            order.TotalAmount = totalAmount;
            orderRepo.Update(order);
            
            _unitOfWork.CommitTran();
            
            _logger.LogInformation($"订单创建成功: {orderId}");
            return orderId;
        }
        catch (Exception ex)
        {
            _unitOfWork.RollbackTran();
            _logger.LogError(ex, "创建订单失败");
            throw;
        }
    }
    
    private string GenerateOrderNo()
    {
        return $"ORD{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(1000, 9999)}";
    }
}

14.7 架构模式

14.7.1 三层架构

项目结构:
├── MyProject.Models          # 实体层
│   ├── Student.cs
│   └── Teacher.cs
├── MyProject.Repository      # 仓储层
│   ├── IRepository.cs
│   ├── Repository.cs
│   ├── IStudentRepository.cs
│   └── StudentRepository.cs
├── MyProject.Service         # 服务层
│   ├── IStudentService.cs
│   └── StudentService.cs
└── MyProject.Api             # 表示层
    └── Controllers
        └── StudentController.cs

14.7.2 DDD架构

// 领域模型(Domain Model)
namespace MyProject.Domain.Models
{
    public class Student : AggregateRoot
    {
        public int Id { get; private set; }
        public string Name { get; private set; }
        public int Age { get; private set; }
        
        // 领域行为
        public void ChangeName(string newName)
        {
            if (string.IsNullOrEmpty(newName))
                throw new DomainException("姓名不能为空");
            
            Name = newName;
            AddDomainEvent(new StudentNameChangedEvent(Id, newName));
        }
    }
}

// 领域仓储接口
namespace MyProject.Domain.Repositories
{
    public interface IStudentRepository
    {
        Student GetById(int id);
        void Add(Student student);
        void Update(Student student);
        void Remove(Student student);
    }
}

// 基础设施层实现
namespace MyProject.Infrastructure.Repositories
{
    public class StudentRepository : IStudentRepository
    {
        private readonly ISqlSugarClient _db;
        
        public StudentRepository(ISqlSugarClient db)
        {
            _db = db;
        }
        
        public Student GetById(int id)
        {
            var entity = _db.Queryable<StudentEntity>()
                .First(s => s.Id == id);
            
            return MapToDomain(entity);
        }
        
        public void Add(Student student)
        {
            var entity = MapToEntity(student);
            _db.Insertable(entity).ExecuteCommand();
        }
        
        public void Update(Student student)
        {
            var entity = MapToEntity(student);
            _db.Updateable(entity).ExecuteCommand();
        }
        
        public void Remove(Student student)
        {
            _db.Deleteable<StudentEntity>()
                .Where(s => s.Id == student.Id)
                .ExecuteCommand();
        }
        
        private Student MapToDomain(StudentEntity entity)
        {
            // 映射到领域模型
            return new Student(entity.Id, entity.Name, entity.Age);
        }
        
        private StudentEntity MapToEntity(Student domain)
        {
            // 映射到持久化实体
            return new StudentEntity
            {
                Id = domain.Id,
                Name = domain.Name,
                Age = domain.Age
            };
        }
    }
}

14.7.3 CQRS模式

// 命令(Command)
public class CreateStudentCommand
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
}

// 命令处理器
public class CreateStudentCommandHandler
{
    private readonly IStudentRepository _repository;
    
    public CreateStudentCommandHandler(IStudentRepository repository)
    {
        _repository = repository;
    }
    
    public int Handle(CreateStudentCommand command)
    {
        var student = new Student
        {
            Name = command.Name,
            Age = command.Age,
            Email = command.Email,
            CreateTime = DateTime.Now
        };
        
        return _repository.Insert(student);
    }
}

// 查询(Query)
public class GetStudentQuery
{
    public int Id { get; set; }
}

// 查询处理器
public class GetStudentQueryHandler
{
    private readonly ISqlSugarClient _db;
    
    public GetStudentQueryHandler(ISqlSugarClient db)
    {
        _db = db;
    }
    
    public StudentDto Handle(GetStudentQuery query)
    {
        return _db.Queryable<Student>()
            .Where(s => s.Id == query.Id)
            .Select(s => new StudentDto
            {
                Id = s.Id,
                Name = s.Name,
                Age = s.Age,
                Email = s.Email
            })
            .First();
    }
}

// 使用MediatR实现CQRS
public class StudentController : ControllerBase
{
    private readonly IMediator _mediator;
    
    public StudentController(IMediator mediator)
    {
        _mediator = mediator;
    }
    
    [HttpPost]
    public async Task<ActionResult<int>> Create([FromBody] CreateStudentCommand command)
    {
        var id = await _mediator.Send(command);
        return Ok(id);
    }
    
    [HttpGet("{id}")]
    public async Task<ActionResult<StudentDto>> Get(int id)
    {
        var query = new GetStudentQuery { Id = id };
        var result = await _mediator.Send(query);
        return Ok(result);
    }
}

14.8 本章小结

本章详细介绍了仓储模式与依赖注入:

  1. 仓储模式:理解了仓储模式的概念、优势和实现方法
  2. 基础仓储:实现了完整的CRUD操作仓储
  3. 泛型仓储:创建了可复用的泛型仓储,支持同步和异步操作
  4. 工作单元:实现了工作单元模式,管理事务和多个仓储
  5. 依赖注入:掌握了与ASP.NET Core和Autofac的集成
  6. 服务层:设计了完整的服务层,封装业务逻辑
  7. 架构模式:学习了三层架构、DDD和CQRS等架构模式

通过本章的学习,您应该能够构建结构清晰、易于维护的企业级应用程序。在下一章(最后一章)中,我们将学习SqlSugar的高级特性与最佳实践,并对整个教程进行总结。