EF. Сохранение/Загрузка "сложных" сущностей в n-tier
От: Аноним  
Дата: 11.06.10 08:32
Оценка:
Привет всем,

разрабатывается распределенное приложение n-tier с использование EF.
Пока только теоретические размышления. Допустим есть три таблицы связанные друг с другом FK:


Родитель -> Ребенок ->   Внук.
--------    -------      -----
ID          ID           ID
            IDРодитель   IDРебенок


получаются примерно следущие сущности:

Родитель -> Ребенок -> Внук
-------- ------- ----


ID          ID         ID
Ребенок[]   Родитель   Ребенок 
            Внук[]


Мне нужно грузить сущьности из бызы, показывать пользователю, обрабатывать, сохранять обратно в базу.
Допустим, следуем следующему сценарию, когда пользователь грузит список детей (ребенок), что бы для начала их увидеть. Одного из них он выбирает, что бы редактировать. И в этот момент, еще не совсем ясно, понядобятся ли ему Родитель и Внук, может быть он не захочеть эти данные менять, а ограничется редактированием данных "ребенка".

Итак, для загрузки списка детей возможно понадобится подобный метод сервиса.
public Ребенок[] GetРебенокList() {
// .. результат отделяется от контекста
}

Не понятно чего когда конкретно грузить. Мне кажется было бы естестенно ограничится списком детей (ребенок), без дозагрузки связанных сущностей.
Допустим пользователь выбирает пользователя для редактирования. Тут бы стоило дозагрузить связанные сущьсности, но как это делать правильно?
Можно попросить сервис:
public Внук[] GetВнукList(Ребенок ID) {
// .. результат отделяется от контекста
}

И присвоить этот список экземпляру Ребенок.

Может было бы лучше, как то делать так:
public ребенок FillВнукLIst(ребенок) {
// подцепляем объект ребенок к "контексту",
// грузим в него внуков
}

Смущает, что нужно передавать весь объект "ребенок", что бы подцепить к нему связанные сущности. Как то криво.

Следующие непонятки возникают, когда необходимо сохранить объект.
Как лучше делать методы сервиса?
Расщиплять объект "ребенок" на составные части? И Вызывать отдельные методы для сохранинея? SaveРебенок(), SAveВнук(), SaveРодитель()

Или вызвать единственный метод SaveРебенок(Ребенок), который как то-сам определяет внутренние связанные объекты, аттачит их в контекст относительно ребенка и сохраняет весь граф данных за один прием.
В этом случае возникают опасения, что если я поменяю угол обозрения, и на сущности буду смотреть со стороны не ребенка, а например внука. То для сохраниения внука SaveВнук, придется заного определять логику добавления внука.

Весь описанный выше бред можно свести к двум вопросам:
— Как организовывать лучше всего дозагрузку связанных сущностей в отделенные от контекста сущности (в распределенных приложениях)?
— Как делать сохранение "сложных" сущностей со связанными данными?
Re: EF. Сохранение/Загрузка "сложных" сущностей в n-tier
От: Аноним  
Дата: 11.06.10 13:12
Оценка:
Что-то я совсем завис. И все молчат.

У меня Entity — классы, расшаренные на сервисе. Клиент работает с прокси.
Скажите, какую стратегию можно применить для дозагрузки объектов в эти прокси классов.
Можно явно, похоже что автоматическая дазагрузка (lazy load) не будет работать.

Я сейчас уже достаточно долго копаюсь по этой проблеме, ничего не найду. Очень много материала посвященному POCO, но я не совсем еще понимаю что это такое, и хотелось бы совета специалистов — это ли мое лекарство?

Забыл указать, что я работаю еще в VS2008, и соответсвенно не самые свежие версии EF и WCF
Re: EF. Сохранение/Загрузка "сложных" сущностей в n-tier
От: IB Австрия http://rsdn.ru
Дата: 11.06.10 14:22
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

А>Весь описанный выше бред можно свести к двум вопросам:

А>- Как организовывать лучше всего дозагрузку связанных сущностей в отделенные от контекста сущности (в распределенных приложениях)?
А>- Как делать сохранение "сложных" сущностей со связанными данными?
Совет простой: вне зависимости от используемой ORM отказаться от сложных сущностей.
У тебя есть коллекции родителей, детей и внуков — в подавляющем большинстве сценариев они все будут нужны по отдельности, какой тогда смысл городить иерархию, а потом изнурительно думать как же с ней работать?
Подобные иерархии есть в предметной области, но тупо воспроизводить их в коде — не самая лучшая идея, так как в коде приходится измываться над сущностями самым прихотливым образом и жесткие иерархические связи имеют даже при самом удачном раскладе, имеют смысл процентах в пятидесяти сценариев (обычно меньше), зато в остальных случаях эту иерархию приходится мучительно преодолевать.
Тем более, что есть LINQ с помощью которого можно соорудить произвольную конструкцию по месту, если вдруг потребуется.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[2]: EF. Сохранение/Загрузка "сложных" сущностей в n-tier
От: Аноним  
Дата: 11.06.10 15:05
Оценка:
IB>Совет простой: вне зависимости от используемой ORM отказаться от сложных сущностей.
IB>У тебя есть коллекции родителей, детей и внуков — в подавляющем большинстве сценариев они все будут нужны по отдельности, какой тогда смысл городить иерархию, а потом изнурительно думать как же с ней работать?
IB>Подобные иерархии есть в предметной области, но тупо воспроизводить их в коде — не самая лучшая идея, так как в коде приходится измываться над сущностями самым прихотливым образом и жесткие иерархические связи имеют даже при самом удачном раскладе, имеют смысл процентах в пятидесяти сценариев (обычно меньше), зато в остальных случаях эту иерархию приходится мучительно преодолевать.

Прежде всего, спасибо за ответ.
Если я вас правильно понимаю, загрузка/сохранение должны осуществляться над простыми объектами, связанные объекты лучше грузить отдельно, так как и работать с ними приходиться отдельно?

Как осуществлять сохранение в таком случае?
public void Save(Родитель, Внук);?
В этом случае предполагается, что сервис, сохраняющий родителей, должен уметь сохранять и внуков.

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

Потом для контроля, что было изменено, нужно уметь определять, были ли загруженны иерархические объекты, были ли они изменены. Тогда, наверное, понадобиться расширять классы свойствами типа IsLoaded, Modifed и т.д. Правильное направление?

IB>Тем более, что есть LINQ с помощью которого можно соорудить произвольную конструкцию по месту, если вдруг потребуется.

Да с этим особых проблем нет. Но приложение распределенное, а потому приходится думать о разумном опросе данных, что бы не порождать лишний трафик
Re[3]: EF. Сохранение/Загрузка "сложных" сущностей в n-tier
От: IB Австрия http://rsdn.ru
Дата: 13.06.10 11:43
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Если я вас правильно понимаю, загрузка/сохранение должны осуществляться над простыми объектами, связанные объекты лучше грузить отдельно, так как и работать с ними приходиться отдельно?

Угу.

А>Как осуществлять сохранение в таком случае?

А>public void Save(Родитель, Внук);?
Прежде всего, убедиться, что действительно есть сценарии, где нужно одновременно сохранять родителей и внуков. Если таки да, то возможны различные варианты, в зависимости от степени любви к SQL-ю, паранойи по отношению к контролю за транзакциям и прочих околоархитектурных нюансов.
1. public void Save(Родитель, Внук);

2. public void Save(Родитель, transaction)
public void Save(Внук, transaction)

3. public void Save(Родитель)
public void Save(Внук), при вызове, все оборачивается в TransactionScope

А> Что бы вызвая метод сохранения родителя, логика сохранения по цепочке вызвала бы иерархическую логику сохранения иерархических объектов.

Вот это не самая лучшая идея. Тут проблема в том, что спустя какое-то время, никогда не будешь знать, что происходит при изменении какого-то одного объекта, какая логика отрабатывается, и какие конкретно данные и запросы уезжают на сиквел. А если, упаси байт, система еще и достаточно хорошо нагружена и какие-нибудь коллизии на стороне сиквела вдруг случились, то будет совсем грустно отслеживать кто виноват и придумывать что со всем этим делать. Та же проблема и с Lazy Loading-ом...

А>Потом для контроля, что было изменено, нужно уметь определять, были ли загруженны иерархические объекты, были ли они изменены. Тогда, наверное, понадобиться расширять классы свойствами типа IsLoaded, Modifed и т.д. Правильное направление?

Можно конечно и так, но опять-таки, как правило это не самый удачный вариант. Но тут чтобы что-либо советовать нужно знать конкретику и прежде всего следует убедиться, что действительно нужно отслеживать изменения... Обычно такой функционал является подпоркой к ORM и сам по себе не нужен.
Мы уже победили, просто это еще не так заметно...
Re[4]: EF. Сохранение/Загрузка "сложных" сущностей в n-tier
От: Аноним  
Дата: 14.06.10 07:42
Оценка:
А>>Если я вас правильно понимаю, загрузка/сохранение должны осуществляться над простыми объектами, связанные объекты лучше грузить отдельно, так как и работать с ними приходиться отдельно?
IB>Угу.
Ок, меня кажется такой подход вполне удовлетворяет.

А>>Как осуществлять сохранение в таком случае?

А>>public void Save(Родитель, Внук);?
IB>Прежде всего, убедиться, что действительно есть сценарии, где нужно одновременно сохранять родителей и внуков. Если таки да, то возможны различные варианты, в зависимости от степени любви к SQL-ю, паранойи по отношению к контролю за транзакциям и прочих околоархитектурных нюансов.
IB>1. public void Save(Родитель, Внук);

IB>2. public void Save(Родитель, transaction)

IB> public void Save(Внук, transaction)

IB>3. public void Save(Родитель)

IB> public void Save(Внук), при вызове, все оборачивается в TransactionScope

С транзакциями придется разобраться, похоже в WCF есть неплохая поддержка через расширения. Спасибо за наводку.

Огромное спасибо, думаю что я после некоторых подвисаний сорвался с мертвой точки.
Re: EF. Сохранение/Загрузка "сложных" сущностей в n-tier
От: FDSC Россия consp11.github.io блог
Дата: 14.06.10 18:05
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>Родитель -> Ребенок ->   Внук.
А>--------    -------      -----
А>ID          ID           ID
А>            IDРодитель   IDРебенок
А>


Всё это можно запихнуть в одну таблицу

Все_живые
---------
ID
parentID


А>Допустим, следуем следующему сценарию, когда пользователь грузит список детей (ребенок), что бы для начала их увидеть. Одного из них он выбирает, что бы редактировать. И в этот момент, еще не совсем ясно, понядобятся ли ему Родитель и Внук, может быть он не захочеть эти данные менять, а ограничется редактированием данных "ребенка".


Ну не грузи, какие проблемы?

А>Итак, для загрузки списка детей возможно понадобится подобный метод сервиса.

А> public Ребенок[] GetРебенокList() {
А> // .. результат отделяется от контекста
А> }

А>Не понятно чего когда конкретно грузить. Мне кажется было бы естестенно ограничится списком детей (ребенок), без дозагрузки связанных сущностей.


Сделай иерархическую структуру в коде, которая будет представлять данные так, как будто всё загрузилось, но используй слабые ссылки и подгрузку того, чего нет (см., например, здесь http://rsdn.ru/article/dotnet/GCnet.xml
Автор(ы): Игорь Ткачев
Дата: 06.12.2002
Алгоритм работы сборщика мусора (garbage collector, далее просто GC), являющегося частью CLR, подробно описан в книге Джефри Рихтера (Jeffrey Richter) «Applied Microsoft .NET Framework Programming». Мы не будем приводить здесь столь же подробное описание этого алгоритма, но обязательно остановимся на некоторых ключевых моментах.
)


А>Допустим пользователь выбирает пользователя для редактирования. Тут бы стоило дозагрузить связанные сущьсности, но как это делать правильно?


В объекте сразу должен быть список, реализованный отдельным классом, который представляет его детей. Т.е. ты должен обращаться к нему на уровне childs[номер ребёнка], сам список-класс будет содержать индексированное свойство, которое будет определять, подгружен ли ребёнок/все дети или нет.

А>Следующие непонятки возникают, когда необходимо сохранить объект.

А>Как лучше делать методы сервиса?
А>Расщеплять объект "ребенок" на составные части? И Вызывать отдельные методы для сохранинея? SaveРебенок(), SAveВнук(), SaveРодитель()

Всё зависит от того, как именно и где ты хочешь сохранять объект
Можно, например, вызывать метод Save у соотв. предка, который будет вызывать Save у каждого потомка вниз по иерархии. Можно сохранять автоматически, как только вообще что-то изменено, тогда каждое сохранение будет только для того объекта, что изменён (и сам объект будет автоматически определять изменён он или нет).


А>В этом случае возникают опасения, что если я поменяю угол обозрения, и на сущности буду смотреть со стороны не ребенка, а например внука. То для сохраниения внука SaveВнук, придется заного определять логику добавления внука.


Почему заново? Тебе всего-навсего нужно будет сохранить внука в БД, зная его номер родителя. Всё. Если при этом нужно будет изменить родителя, сохранишь и родителя отдельно.

У тебя, чел, аналитический шок — слишком много думаешь. Просто делай, если что — поменяешь.

А>Весь описанный выше бред можно свести к двум вопросам:

А>- Как организовывать лучше всего дозагрузку связанных сущностей в отделенные от контекста сущности (в распределенных приложениях)?

Используя слабые ссылки и реализовав структуру классов так, что они представляют все данные уже загруженными

А>- Как делать сохранение "сложных" сущностей со связанными данными?


Определять, что именно связано, что изменено, и сохранять. Причём важно, чтобы каждый объект сам знал, изменён он или нет и должен ли он сохранить связанные с ним сущности или нет.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.