Заставить мою единицу работы ... ну, работать! - PullRequest
4 голосов
/ 08 апреля 2011

Я выполняю Единицу работы. Это часть моего интерфейса:

public interface IUnitOfWork
{
    void Add(object entity);
    void Update(object entity);
    void Delete(object entity);        
    void Commit();
}

Как видно из примеров, которые я нашел в Интернете или в книгах, единица работы вынуждена работать с типом "объект", так как мы можем добавлять любой объект "типа" к uow.

Ничего страшного, пока не наступит время Commit (). Когда я фиксирую, учитывая тип сущности, мне нужно найти хранилище на основе типа сущности, а затем вызвать соответствующее действие.

Например, у меня есть тип сущности с именем Expert

public class Expert
{
    public object ID { get; set; }
    public string Name { get; set; }
}

У эксперта есть репозиторий с именем ExpertRepository. Все репозитории в моем приложении реализуют IRepository:

public interface IRepository<T>
{
    void Create(T item);
    void Update(T item);
    void Delete(T item);
}

public class ExpertRepository : IRepository<Expert>
{        
    public void Create(Expert item)
    {
        //TSQL to insert
    }

    public void Update(Expert item)
    {
        //TSQL to update
    }

    public void Delete(Expert item)
    {
        //TSQL to delete
    }
}

Я хочу уточнить, что мои репозитарии не несут ответственности за добавление, обновление или удаление сущности из моего uow, скорее, у меня будет новый потребляющий код (возможно, на служебном уровне), обновляющий uow, и затем добавьте непосредственно к нему ... когда мое приложение будет готово, оно вызовет Commit ().

Это делает две вещи. Это позволяет моему потребляющему коду решить, как он хочет, чтобы сущность сохранялась. Либо код потребления может вызвать .Create () непосредственно в репозитории, чтобы сохранить сущность без uow, либо код потребления может запустить uow, вызвать .Add () для uow, а затем, когда вызывается .Commit (), UOW пройдет через все сущности, и по типу действия (добавить, обновить, удалить), создать новый соответствующий репозиторий и выполнить код TSQL.

Теперь проблема, с которой я сталкиваюсь, заключается в том, что я зацикливаюсь на коллекциях Add, Update и Delete в моем UOW. Вот фрагмент кода:

public void Commit()
{
using (TransactionScope tx = new TransactionScope())
    {
        try
        {
            foreach (object item in addedItems)
            {
                if (item.GetType() == typeof(Expert))
                {
                    IRepository<Expert> repository = new ExpertRepository();
                    repository.Create((Expert)item);
                }
            }
        }
    }
}

Мне нужно разрешить тип объекта, который находится в коллекции объектов, через переменную item. Затем мне нужно обновить репозиторий этой сущности (также предоставив правильный тип для интерфейса IRepository), а затем вызвать .Create ().

Это все хорошо, но я не хочу, чтобы эти условные проверки для каждой возможной сущности, для интерфейса сущности и хранилища сущности находились в моем распоряжении. Это очень, очень плохо.

Я знаю, что здесь может помочь контейнер IoC (например, Unity), но есть ли контейнер IoC, который может разрешать универсальные типы во время выполнения? Я спрашиваю, что b / c IRepository должен быть правильно напечатан, чтобы быть переменной, содержащей экземпляр хранилища данной сущности.

Я принял некоторые дизайнерские решения, такие как строгая типизация с репозиториями, а не с UOW. Например, я не хочу, чтобы метод .Create () находился в репозитории, который принимает объект типа, особенно. поскольку мои репозитории имеют непосредственное отношение к моим сущностям (Expert, ExpertRepository).

Я также решил, что, поскольку большинство вызовов репозитория одинаковы, мне не нужен интерфейс для каждого репозитория (иначе, ExpertRepository реализует IExpertRepository). Это не имеет смысла, я думаю, что использование дженериков - вот ответ.

Но все это сводится к проблеме в моем ух. Как мне получить то, что мне нужно для правильной реализации.

Будем благодарны за любые предложения или указатели в правильном направлении.

Спасибо!

1 Ответ

1 голос
/ 08 апреля 2011

IoC - это путь. Некоторые из них поддерживают открытые дженерики. Давайте возьмем StructureMap в качестве примера . Вам нужно иметь регистрационный код, похожий на этот:

// default implementation
x.For(typeof(IRepository<>)).Use(typeof(DefaultRepository<>)); 
// specific implementations
x.For<IRepository<Expert>>().Use<ExpertRepository>(); 

И тогда ваш Commit метод может просто запросить у контейнера реализацию для данного типа:

_container.ForGenericType(typeof(IRepository<>))
                .WithParameters(item.GetType())
                .GetInstanceAs<IRepository>();

(Вам понадобится не универсальный интерфейс IRepository, который будет покрывать потребности вашего Commit метода, но я считаю, что это не проблема, когда реализации могут отличаться).

...