Реализация общего репозитория с таблично-независимыми методами - PullRequest
0 голосов
/ 06 марта 2019

Я работаю над рефакторингом персистентного слоя, чтобы использовать настоящий универсальный репозиторий, и хочу минимизировать количество похожих запросов, выполняемых в разных таблицах - подумайте, например, получить по идентификатору из таблицы a, b или c, где запрос отличается только таблицей.

Мой репозиторий до сих пор выглядит так:

public interface IRepository<T>
{
    void Insert(T entity);
    void Update(T entity);
}

public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    /// ctor stuff omitted ...

    public void Insert(TEntity entity)
    {
        _db.Insert<TEntity>(entity);
    }

    public void Update(TEntity entity)
    {
        _db.Update<TEntity>(entity);
    }
}

public interface IDerivedRepository : IRepository<MyEntity>
{
    // defines interface methods not found on the base IRepository
}

public class DerivedRepository : BaseRepository<MyEntity>, IDerivedRepository
{
    // implements methods defined on IDerivedRepository, and inherits Insert and Update from BaseRepository
}

Это прекрасно работает, поскольку любой новый репозиторий может наследовать методы, определенные в базовом репо, которые не зависят от типа, поскольку я могу просто отправлять сущность, а мой ORM (NPoco) управляет вставкой / обновлением.

Я хочу расширить это, чтобы разрешить общие базовые определения для простых методов типа get / fetch - get по id или простой подсчет, являющийся очевидным примером. В настоящее время я реализую их в соответствующем репозитории, поэтому в итоге получаю несколько методов репозитория (в отдельных репозиториях), вызывающих по существу один и тот же код.

Пример ниже упрощен (_db управляет областью действия и т. Д.), Но подчеркивает то, чего я пытаюсь избежать - повторяющиеся методы GetById, где таблица и тип возвращаемого значения отличаются

public class DerivedRepositoryA : BaseRepository<A>, IDerivedARepository
{
    public A GetById(int id) {
        return _db.Fetch<A>("select * from TableA where id = @0", id);
    }
}

public class DerivedRepositoryB : BaseRepository<B>, IDerivedBRepository
{
    public B GetById(int id) {
        return _db.Fetch<B>("select * from TableB where id = @0", id);
    }
}

public class DerivedRepositoryC : BaseRepository<C>, IDerivedCRepository
{
    public C GetById(int id) {
        return _db.Fetch<C>("select * from TableC where id = @0", id);
    }
}

Возможно ли это, и как я могу это сделать?

Ответы [ 2 ]

1 голос
/ 06 марта 2019

Приведенная ниже реализация BaseRepository<TEntity> использует имя типа в качестве имени таблицы по умолчанию, но допускает использование пользовательского имени таблицы, которое отличается от имени типа, если требуется.

public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    private readonly string tableName;

    public BaseRepository() : this(typeof(TEntity).Name)
    {

    }

    public BaseRepository(string tableName)
    {
        this.tableName = tableName;
    }

    public TEntity GetById(int id)
    {
        return _db.Fetch<TEntity>($"select * from Table{tableName} where id = {id}");
    }
}
0 голосов
/ 04 апреля 2019

Вам не нужно имя таблицы, это будет работать

    return _db.Single<TEntity>("where id = @id", id);  //Or Fetch

Вы можете сделать что-то подобное и позволить NPoco обрабатывать SQL. Вы также можете использовать это для сохранения () или удаления () также

    public T GetByID<T>(Int32 ID)
    {
        try
        {
            if (ID == 0)
                throw (new ArgumentNullException("ID cannot be 0"));

            return _db.SingleOrDefaultById<T>(ID);
        }
        catch { throw; }
    }
...