Saturday, March 29, 2008

Entity Framework rollback: Часть 1. Постановка задачи

Этим постом я бы хотел начать серию сообщений о реализации отката (rollback) контекста в Entity Framework (EF). Я столкнулся с этим на своем текущем проекте и хотел бы поделиться тем, что у меня получилось и, возможно, получить дельные советы от тех, кто это реализовал по-другому или у кого есть идеи по улучшению реализации.

Итак, начнем с того, что на данный момент в EF (beta 3) нет полноценной возможности сохранять изменения, которые содержаться в контексте в памяти и потом откатываться к ним. Есть варианты отката изменений из контекста до текущего состояния базы данных, но и только.

Теперь постановка задачи: представьте себе приложение ASP.NET или WinForms, в котором пользователь может взять какой-нибудь набор связанных или не связанных объектов (Поставщики, Заказы, пр.), отредактировать эти объекты и потом нажать кнопочку Save, которая сохранит данные в базу данных. Или не нажать эту кнопочку, а нажать вместо нее Cancel, что отменит изменения. Ничего сложного, скажете вы. Можно: а) дать пользователю ввести все изменения, нигде их не сохраняя, а потом просто занести в базу по нажатию кнопки, б) если же все же нужно сохранять промежуточные изменения (допустим, если нужно добавить несколько объектов подряд, или нескольких объектов в разных диалогах), то их можно сделать в контексте в памяти, а потом по нажатию кнопки одним махом сохранить или не сохранить в базу. Возражения правильные и предложенные решения работают. Однако существует еще один сценарий, который не покрывается этими двумя вариантами. По этому сценарию пользователь делает промежуточные изменения, переходит к следующим, снова делает какие-то промежуточные изменения, а потом решает откатиться до точки между этими изменениями. Например, он открыл окно редактирования объекта, увидел список связанных объектов, потом добавил пару объектов в список (первое промежуточное изменение), потом кликнул на кнопке редактирования одного из объектов из списка и получил новое диалоговое окно, в котором находится список связанных объектов, где он также может добавить несколько объектов (второе промежуточное изменение) и нажать Cancel. По нажатию на Cancel мы должны откатить второе промежуточное изменение и выйти на точку, где у нас есть только первое изменение. А вот уже эта задача, к сожалению, не решается стандартными средствами EF. Вы не можете откатиться до произвольной точки в памяти, вы можете лишь откатиться до состояния базы данных. Зато эта задача решается с помощью терпения и напильника :)

Перед тем, как идти дальше, нужно разобраться в терминологии и предмете. Контекст в EF является отсоединенным источником данных (как DataSet или DataTable). То есть по-хорошему он кэширует однажды полученные из базы данных результаты и в дальнейшем по запросам лишь проверяет, нет ли новых записей (подробнее об этом механизме я, возможно, расскажу после того, как закончу текущую серию). Таким образом, если мы выбрали данные в контекст, то в грубом приближении мы можем считать, что после этого мы работаем лишь с данными, которые находятся в памяти. Повторяю: это не так в реальности, но на данном этапе нам этого хватит. Изменения, произведенные в памяти, не сохраняются в базу до тех пор пока мы явно не вызовем метод SaveChanges у контекста. Понимание этого факта необходимо для дальнейшего разбора.Также замечу, что здесь и в дальнейшем, когда я говорю «контекст», я понимаю экземпляр класса ObjectContext или унаследованного от него вашего класса.

Кому интересно узнать больше про EF уже сейчас, отправляю сюда:

The ADO.NET Entity Framework (MSDN) ADO.NET Entity Framework (Wikipedia) Продолжение в следующих постах.

No comments:

Post a Comment