Как вернуть контекст ef4 или хотя бы некоторые объекты к их исходным значениям? - PullRequest
2 голосов
/ 14 июня 2011

Сценарий:

  1. Извлечение некоторых сущностей
  2. Обновление некоторых свойств для этих сущностей
  3. Вы выполняете некую бизнес-логику, которая требует, чтобы у вас больше не былоэти свойства обновлены;вместо этого вы должны вставить несколько новых сущностей, документирующих результаты вашей бизнес-логики.
  4. Вставить упомянутые новые сущности
  5. SaveChanges ();

Очевидно, что в приведенном выше примере вызываетсяSaveChanges () будет не только вставлять новые сущности, но и обновлять свойства исходных сущностей.До того, как мне удалось перестроить свой код таким образом, чтобы изменения в контексте (и его сущностях) были сделаны только тогда, когда я точно знал, что хочу сохранить все свои изменения, однако это не всегда возможно.Итак, вопрос в том, как лучше всего справиться с этим сценарием?Я не работаю с контекстом напрямую, а через репозитории, если это имеет значение.Есть ли простой способ вернуть сущности к их первоначальным значениям?Какова лучшая практика в сценарии такого рода?

Обновление

Хотя я не согласен с Ладиславом, что бизнес-логику следует перестроить таким образом, чтобы проверка всегда происходилаперед любым изменением сущностей я согласен с тем, что решение действительно должно сохранять желаемые изменения в другом контексте.Причина, по которой я не согласен, заключается в том, что моя бизнес-транзакция достаточно длинная, и проверка или проверка ошибок, которые могут произойти в конце транзакции, не всегда очевидны заранее.Представьте себе елку, которую вы украшаете огнями сверху вниз, вы уже изменили дерево к тому времени, как работаете над нижними ветвями.Что произойдет, если один из огней сломается?Вы хотите откатить все свои изменения, но вы хотите создать некоторые ОШИБКИ.Как предположил Ладислав, самым простым способом было бы сохранить сущности ОШИБКИ в другом контексте, позволяя истечь исходному (с измененным метафорическим деревом) без вызова SaveChanges.

Теперь в моей ситуацииЯ использую Ninject для внедрения зависимости, внедряя один EF-контекст во все мои репозитории, которые входят в сферу обслуживания верхнего уровня.Это означает, что мои классы бизнес-уровня на самом деле не контролируют создание новых контекстов EF.Мало того, что они не имеют доступа к контексту EF (помните, что они работают через репозитории), но внедрение уже произошло выше в иерархии объектов.Единственное решение, которое я нашел, - это создать другой класс, который будет использовать Ninject для создания нового UOW внутри него.

//business logic executing against repositories with already injected and shared (unit of work) context
Tree = treeRepository.Get();
Lights = lightsRepsitory.Get();

//update the tree as you're decorating it with lights

if(errors.Count == 0)
{
    //no errors, calling SaveChanges() on any one repository will commit the entire UOW as they all share the same injected EF context
    repository1.SaveChanges();  
}
else
{
    //oops one of the lights broke, we need to insert some Error entities
    //however if we just add id to the errorRepository and call SaveChanges() the modifications that happened
    //to the tree will also be committed.
    TreeDecoratorErroHandler.Handle(errors);    
}

internal class TreeDecoratorErroHandler
{
    //declare repositories
    //constructor that takes repository instances

    public static void Handle(IList<Error> errors)
    {
        //create a new Ninject kernel
        using(Ninject... = new Ninject...)
        {
            //this will create an instance that will get injected with repositories sharing a new EF instance
            //completely separate from the one outside of this class
            TreeDecoratorErroHandler errorHandler = ninjectKernel.Get<TreeDecoratorErroHandler>();
            //this will insert the errors and call SaveChanges(), the only changes in this new context are the errors
            errorHandler.InsertErrors(errors);
        }       
    }

    //other methods
}

Ответы [ 2 ]

1 голос
/ 14 июня 2011

Вы должны определенно использовать новый контекст для этого. Контекст - это единица работы, и как только ваша бизнес-логика говорит: «Эй, я не хочу обновлять эту сущность», тогда сущность не является частью единицы работы. Вы можете отсоединить объект или создать новый контекст.

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

0 голосов
/ 14 июня 2011

Взгляните на ObjectContext.Refresh с RefreshMode.Store. Я думаю, что это будет делать то, что вы хотите. Я полагаю, что запуск нового контекста приведет к тому же самому, но не будет таким аккуратным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...