PetaPoco + единица работы + шаблон репозитория

Код ниже, кажется, работает, используя это:

var unitOfWorkProvider = new PetaPocoUnitOfWorkProvider();
var repository = new FakeRepository();
var fake = new Fake
{     
    // etc.
};

using (var uow = unitOfWorkProvider.GetUnitOfWork("BlaConnectionString"))
{
    repository.Insert(uow, fake);
    uow.Commit();
}

который может в конечном итоге перейти на сервисный уровень. Я был бы признателен за любые отзывы, чтобы улучшить этот код.

public interface IUnitOfWork : IDisposable
{
    void Commit();
    Database Database { get; }
}

public interface IUnitOfWorkProvider
{
    IUnitOfWork GetUnitOfWork(string connectionString);
}

public class PetaPocoUnitOfWorkProvider : IUnitOfWorkProvider
{
    public IUnitOfWork GetUnitOfWork(string connectionString)
    {
        return new PetaPocoUnitOfWork(connectionString);
    }
}

public interface IRepository<T>
{
    void Insert(IUnitOfWork unitOfWork, T entity);
    void Update(IUnitOfWork unitOfWork, T entity);
    void Delete(IUnitOfWork unitOfWork, T entity);
    T Fetch(IUnitOfWork unitOfWork, long uid);
}

public class PetaPocoUnitOfWork : IUnitOfWork
{
    private readonly Transaction _petaTransaction;
    private readonly Database _database;

    public PetaPocoUnitOfWork(string connectionString)
    {
        _database = new Database(connectionString);
        _petaTransaction = new Transaction(_database);
    }

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

    public Database Database
    {
        get { return _database; }
    }

    public void Commit()
    {
        _petaTransaction.Complete();
    }
}

public class FakeRepository : IRepository<Fake>
{
    public void Insert(IUnitOfWork unitOfWork, Fake entity)
    {
        unitOfWork.Database.Save(entity);
    }

    public void Update(IUnitOfWork unitOfWork, Fake entity)
    {
        unitOfWork.Database.Update(entity);
    }

    public void Delete(IUnitOfWork unitOfWork, Fake entity)
    {
        unitOfWork.Database.Delete(entity);
    }

    public FakeJobFact Fetch(IUnitOfWork unitOfWork, long uid)
    {
        return unitOfWork.Database.Fetch<Fake>("SELECT * FROM Fakes WHERE [FakeId] = @0", uid).FirstOrDefault();
    }
}

PS:

Я адаптировал код в соответствии с текущим ответом @Plebsori:

public abstract class BaseRepository<T>
{
    protected IDatabase Database
    {
        get
        {
        return UnitOfWork.Current;
        }
    }

    public void Insert(T entity)
    {
        Database.Save(entity);
    }

    public void Update(T entity)
    {
        Database.Update(entity);
    }

    public void Delete(T entity)
    {
        Database.Delete(entity);
    }
}

public interface IRepository<T>
{
    void Insert(T entity);
    void Update(T entity);
    void Delete(T entity);
    T Fetch(long uid);
}

public interface IUnitOfWork : IDisposable
{
    void Commit();
    Database Database { get; }
}

public interface IUnitOfWorkProvider
{
    IUnitOfWork GetUnitOfWork(string connectionString);
}

public class PetaPocoUnitOfWork : IUnitOfWork
{
    private readonly Transaction _petaTransaction;
    private readonly Database _database;

    public PetaPocoUnitOfWork(string connectionString)
    {
        _database = new Database(connectionString);
        _petaTransaction = new Transaction(_database);
    }

    public void Dispose()
    {
        UnitOfWork.Current = null;
        _petaTransaction.Dispose();
    }

    public Database Database
    {
        get { return _database; }
    }

    public void Commit()
    {
        _petaTransaction.Complete();
    }
}

public class PetaPocoUnitOfWorkProvider : IUnitOfWorkProvider
{
    public IUnitOfWork GetUnitOfWork(string connectionString)
    {
        if (UnitOfWork.Current != null)
        {
        throw new InvalidOperationException("Existing unit of work.");
        }

        var petaPocoUnitOfWork = new PetaPocoUnitOfWork(connectionString);
        UnitOfWork.Current = petaPocoUnitOfWork.Database;
        return petaPocoUnitOfWork;
    }
}

public static class UnitOfWork
{
    [ThreadStatic] public static IDatabase Current;
}

person cs0815    schedule 01.02.2016    source источник
comment
Не могли бы вы уточнить, каким должен быть интерфейс IDatabase? Кроме того, вы были довольны этим подходом?   -  person Mathieu    schedule 16.10.2017


Ответы (1)


Вам может нравиться или не нравиться, но вот как я убрал из интерфейса передачу единицы работы и единицы работы.

var unitOfWorkProvider = new PetaPocoUnitOfWorkProvider();
var repository = new FakeRepository();
var fake = new Fake
{     
    // etc.
};

using (var uow = unitOfWorkProvider.GetUnitOfWork("BlaConnectionString"))
{
    repository.Insert(fake);
    uow.Commit();
}

Код

public interface IUnitOfWorkProvider
{
    IUnitOfWork GetUnitOfWork(string connectionString);
}

public static class UnitOfWork
{
    [ThreadStatic]
    public static IUnitOfWork Current { get; set; }
}

public class PetaPocoUnitOfWorkProvider : IUnitOfWorkProvider
{
    public IUnitOfWork GetUnitOfWork(string connectionString)
    {
        if (UnitOfWork.Current != null) 
        {
           throw new InvalidOperationException("Existing unit of work.");
        }
        UnitOfWork.Current = new PetaPocoUnitOfWork(connectionString);
        return UnitOfWork.Current;
    }
}

public interface IRepository<T>
{
    void Insert(T entity);
    void Update(T entity);
    void Delete(T entity);
    T Fetch(long uid);
}

public class PetaPocoUnitOfWork : IUnitOfWork
{
    private readonly Transaction _petaTransaction;
    private readonly Database _database;

    public PetaPocoUnitOfWork(string connectionString)
    {
        _database = new Database(connectionString);
        _petaTransaction = new Transaction(_database);
    }

    public void Dispose()
    {
        UnitOfWork.Current = null;
        _petaTransaction.Dispose();
    }

    public Database Database
    {
        get { return _database; }
    }

    public void Commit()
    {
        _petaTransaction.Complete();
    }
}

public abstract class BaseRepository<T> : IRepository<T>
{
    protected IDatabase Db
    {
        get
        {
            return UnitOfWork.Current;
        }
    }
}

public class FakeRepository : BaseRepository<T>
{
    public void Insert(Fake entity)
    {
        Db.Save(entity);
    }

    public void Update(Fake entity)
    {
        Db.Update(entity);
    }

    public void Delete(Fake entity)
    {
        Db.Delete(entity);
    }

    public FakeJobFact Fetch(long uid)
    {
        return Db.Fetch<Fake>("SELECT * FROM Fakes WHERE [FakeId] = @0", uid).FirstOrDefault();
    }
}
person Plebsori    schedule 01.02.2016
comment
Мне нравится это спасибо. Да, прохождение uow все время не кажется правильным. Просто любопытно - гарантирует ли UnitOfWork.Current, что репо использует только uow, который является частью области использования? Спасибо! - person cs0815; 02.02.2016
comment
Обновлен пример кода для создания, если существует другая единица работы. Это остановит вложенную единицу работы. Однако, поскольку статический поток является статическим потоком, этот дизайн будет означать, что каждый из нескольких потоков будет иметь свою собственную область видимости. - person Plebsori; 02.02.2016
comment
какова цель ThreadStatic, если Current не статично? - person cs0815; 03.02.2016
comment
Как правило, ваш UnitOfWork не строит - person cs0815; 03.02.2016
comment
Также BaseRepository не реализует интерфейс - person cs0815; 03.02.2016
comment
Обновлен код для вас. Я пишу это от руки, чтобы дать вам представление - person Plebsori; 04.02.2016
comment
Спасибо - впечатляет, что вы пишете это от руки. Я даже жить не мог без решарпера (-: - person cs0815; 04.02.2016
comment
Извините, но ваш BaseRepository должен абстрагироваться и реализовать интерфейс в целом (например, использовать T)? Также не уверен, что означает защищенный IDatabase Db => UnitOfWork.Current? Извини ... - person cs0815; 04.02.2016
comment
Ах да, извините, это должно быть абстрактно. (обновлено). Другой — синтаксис С# 6, обновленный до версии 5. - person Plebsori; 04.02.2016
comment
Я продолжаю пытаться заставить это работать, но в настоящее время застрял с PetaPocoUnitOfWorkProvider - он выдает ошибки. Было бы действительно здорово, если бы вы могли попытаться собрать это на своем конце и опубликовать правильный код? - person cs0815; 06.02.2016
comment
есть ли шанс получить обратную связь, пожалуйста? Постарайтесь заставить ваш код работать сегодня. - person cs0815; 08.02.2016
comment
Я попытался адаптировать ваш ответ, чтобы заставить его работать. Мою попытку можно найти в разделе PS моего исходного вопроса. Если вы считаете, что это правильно, и как только вы адаптируете свой ответ, я приму его. - person cs0815; 08.02.2016
comment
Я не вижу ничего, что запускает транзакцию? Таким образом, все операции с базой данных завершаются, даже если на полпути возникает исключение? Нигде нет вызова _database.BeginTransaction()? - person NickG; 15.04.2020
comment
PetaPocoUnitOfWork обрабатывает транзакцию БД. Database и Transaction относятся к типу PetaPoco. @NickG не стесняйтесь открывать вопрос GH, если вам нужна дополнительная информация. - person Plebsori; 17.04.2020