Структурирование проекта на ASP.NET Core с целью уменьшения дублирования кода — это важный аспект разработки, который позволяет упростить поддержку и расширяемость приложения. Вот несколько подходов, которые помогут вам организовать проект более эффективно:
### 1. Использование Generics для репозиториев
Одним из наиболее распространенных способов избежать дублирования кода в репозиториях является использование обобщённых (generic) классов. Вы можете создать базовый репозиторий, который будет реализовывать общие CRUD операции.
```csharp
public interface IRepository<TEntity> where TEntity : class
{
Task<IEnumerable<TEntity>> GetAllAsync();
Task<TEntity> GetByIdAsync(int id);
Task AddAsync(TEntity entity);
Task UpdateAsync(TEntity entity);
Task DeleteAsync(int id);
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly DbContext _context;
private readonly DbSet<TEntity> _dbSet;
public Repository(DbContext context)
{
_context = context;
_dbSet = context.Set<TEntity>();
}
public async Task<IEnumerable<TEntity>> GetAllAsync() => await _dbSet.ToListAsync();
public async Task<TEntity> GetByIdAsync(int id) => await _dbSet.FindAsync(id);
public async Task AddAsync(TEntity entity) => await _dbSet.AddAsync(entity);
public async Task UpdateAsync(TEntity entity) => _dbSet.Update(entity);
public async Task DeleteAsync(int id)
{
var entity = await GetByIdAsync(id);
if (entity != null)
_dbSet.Remove(entity);
}
}
```
С помощью такого подхода, вы можете создать репозитории для конкретных сущностей, наследуя их от базового класса:
```csharp
public class UserRepository : Repository<User>, IUserRepository
{
public UserRepository(DbContext context) : base(context) { }
}
public class BookRepository : Repository<Book>, IBookRepository
{
public BookRepository(DbContext context) : base(context) { }
}
```
### 2. Создание базовых сервисов
Аналогично репозиториям, вы можете создать базовый сервис для обработки логики, относящейся к CRUD операциям. Это поможет избежать дублирования в сервисах.
```csharp
public interface IService<TEntity>
{
Task<IEnumerable<TEntity>> GetAllAsync();
Task<TEntity> GetByIdAsync(int id);
Task AddAsync(TEntity entity);
Task UpdateAsync(TEntity entity);
Task DeleteAsync(int id);
}
public class BaseService<TEntity> : IService<TEntity> where TEntity : class
{
private readonly IRepository<TEntity> _repository;
public BaseService(IRepository<TEntity> repository)
{
_repository = repository;
}
public Task<IEnumerable<TEntity>> GetAllAsync() => _repository.GetAllAsync();
public Task<TEntity> GetByIdAsync(int id) => _repository.GetByIdAsync(id);
public Task AddAsync(TEntity entity) => _repository.AddAsync(entity);
public Task UpdateAsync(TEntity entity) => _repository.UpdateAsync(entity);
public Task DeleteAsync(int id) => _repository.DeleteAsync(id);
}
```
Теперь вы можете создать конкретные сервисы для каждой сущности, наследуясь от базового сервиса.
```csharp
public class UserService : BaseService<User>, IUserService
{
public UserService(IUserRepository repository) : base(repository) { }
}
```
### 3. Использование паттерна "Unit of Work"
Если у вас есть несколько репозиториев, которые работают с одним и тем же контекстом базы данных, вы можете использовать паттерн "Unit of Work", чтобы объединить их в одном классе.
```csharp
public interface IUnitOfWork : IDisposable
{
IUserRepository Users { get; }
IBookRepository Books { get; }
IOrderRepository Orders { get; }
Task SaveAsync();
}
public class UnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
public IUserRepository Users { get; }
public IBookRepository Books { get; }
public IOrderRepository Orders { get; }
public UnitOfWork(DbContext context)
{
_context = context;
Users = new UserRepository(_context);
Books = new BookRepository(_context);
Orders = new OrderRepository(_context);
}
public async Task SaveAsync() => await _context.SaveChangesAsync();
public void Dispose() => _context.Dispose();
}
```
### 4. Использование MediatR
Использование MediatR для обработки команд и запросов также может помочь уменьшить дублирование кода в Use Cases. Вмест