Как поделиться общим кодом с зависимостью .NET Core

Мой вопрос заключается в использовании внедрения зависимостей в .NET Core. Я могу создавать разные репозитории для некоторых операций CRUD и предоставлять их API. Однако, делая это так, как показано ниже, я получаю много повторяющегося кода, поскольку мне приходится создавать новые методы для добавления, обновления и удаления для каждого класса. Как я могу это сделать, но имея для этого общий код, поскольку единственные вещи, которые действительно меняются, - это сущности и используемая таблица. Вы также можете увидеть тот же код на .NET Fiddle.

Я удалил как можно больше несущественного кода...

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

public interface IBaseDao
{
    Task SaveChangesAsync(CancellationToken cancellationToken);
}

public interface ICrudRepository<TModel, TId> : IBaseDao
{
    public Task<TModel> AddAsync(TModel model, CancellationToken cancellationToken);
    public Task<TModel> UpdateAsync(TModel model, CancellationToken cancellationToken);
    public Task DeleteAsync(TId id, string userName, CancellationToken cancellationToken);
}

public interface IPersonCrudRepository : ICrudRepository<Person, int>
{
}

public abstract class BaseDao : IBaseDao
{
    protected BaseDao(CustomDbContext dbContext) =>
        this.CustomDbContext = dbContext;

    protected CustomDbContext CustomDbContext { get; set; }

    public virtual async Task SaveChangesAsync(CancellationToken cancellationToken) =>
        _ = await this.CustomDbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}

public class CustomDbContext : DbContext
{
    public CustomDbContext(DbContextOptions<CustomDbContext> options)
        : base(options)
    {
    }
}

public class PersonCrudRepository : BaseDao, IPersonCrudRepository
{
    public PersonCrudRepository(CustomDbContext dbContext)
        : base(dbContext)
    {
    }

    public async Task<Person> AddAsync(Person model, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(model);

        var entity = (await this.CustomDbContext
            .Set<Person>()
            .AddAsync(model, cancellationToken)
            .ConfigureAwait(false)).Entity;

        await this.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
        return entity;
    }

    public async Task DeleteAsync(int id, string userName, CancellationToken cancellationToken)
    {
        var entity = new Person { Id = id };
        _ = this.CustomDbContext.Set<Person>().Attach(entity);
        entity.ModifiedBy = userName;
        entity.StatusId = (byte)Status.Inactive;

        await this.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
    }

    public async Task<Person> UpdateAsync(Person model, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(model);

        _ = this.CustomDbContext.Set<Person>().Attach(model);
        await this.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

        return model;
    }
}

public class Person : ChangeTracker
{
    public int Id { get; set; }
    public string Name { get; set; } = default!;
}

public abstract class ChangeTracker
{
    public string ModifiedBy { get; set; }
    public byte StatusId { get; set; }
}

public enum Status
{
    Active = 1,
    Inactive = 2,
}

public class Startup
{
    public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
    {
    }

    public virtual void ConfigureServices(IServiceCollection services) =>
        _ = services.AddScoped<IPersonCrudRepository, PersonCrudRepository>();
}

Вы думали об универсальном абстрактном классе? когда я работал с dapper, я просто решил это таким образом, другим подходом были бы методы расширения

DonMiguelSanchez 04.11.2022 16:12

Помогает ли ответ по этой ссылке? stackoverflow.com/questions/68273081/abstract-database-acces‌​s/…

ChrisBD 04.11.2022 17:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете сделать что-то общее ->

//создаем общий интерфейс

    public interface IBaseRepository<T>
    {
        public IQueryable<T> GetAll();
        public T? GetById(Guid id);
        public Task<T?> GetByIdAsync(Guid id);
        public IQueryable<T> GetByCondition(Expression<Func<T, bool>> expression);
        public void Create(T entity);
        public Task CreateAsync(T entity);
        public void Update(T entity);
        public void Delete(T entity);
        public void Save();
        public Task SaveAsync();
    }

//создаем универсальный абстрактный класс

public abstract class BaseRepository<T> : IBaseRepository<T> where T : class
{
    protected readonly CustomDbContext _dbContext;

    protected BaseRepository(CustomDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IQueryable<T> GetAll() => _dbContext.Set<T>().AsNoTracking();
    public T? GetById(Guid id) => _dbContext.Set<T>().Find(id);
    public async Task<T?> GetByIdAsync(Guid id) => await _dbContext.Set<T>().FindAsync(id);
    public IQueryable<T> GetByCondition(Expression<Func<T, bool>> expression) => _dbContext.Set<T>().Where(expression);
    public void Create(T entity) => _dbContext.Set<T>().Add(entity);
    public async Task CreateAsync(T entity) => await _dbContext.Set<T>().AddAsync(entity);
    public void Update(T entity) => _dbContext.Set<T>().Update(entity);
    public void Delete(T entity) => _dbContext.Set<T>().Remove(entity);
    public void Save() => _dbContext.SaveChanges();
    public async Task SaveAsync() => await _dbContext.SaveChangesAsync();
}

//создаем интерфейс репозитория

public interface IExampleRepository : IBaseRepository<ExampleEntityClass>
{
}

// создайте свой конкретный класс репозитория

public class Repository : BaseRepository<ExampleEntityClass>, IExampleRepository 
{
    public Repository (CustomDbContext dbContext) : base(dbContext)
    {
    }
}

я думаю, что это хорошее решение, я бы изменил методы и объявил их виртуальными, на всякий случай, если какой-либо из них нуждается в альтернативной реализации.

DonMiguelSanchez 05.11.2022 08:39

Это был правильный ответ для моих нужд. Я поделился своими изменениями на .NET Fiddle

vcliment89 15.11.2022 18:03

Другие вопросы по теме