Сценарий:
- Извлечение некоторых сущностей
- Обновление некоторых свойств для этих сущностей
- Вы выполняете некую бизнес-логику, которая требует, чтобы у вас больше не былоэти свойства обновлены;вместо этого вы должны вставить несколько новых сущностей, документирующих результаты вашей бизнес-логики.
- Вставить упомянутые новые сущности
- 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
}