Имеется система, использующая модель предметной области + мапперы для ее отображения на реляционную БД. Согласно правилу паттерна, бизнес-классы системы не могут напрямую обращаться к мапперам. За них это делает реестр (он-же unit of work).
Т.е. если мне нужен новый объект, я иду в реестр, ищу его там по идентификатору (а метод поиска реестра уже сам определяет где взять объект, если уже загружен — то в кэше, если нет — обратиться к мапперу).
Но как быть с методами отчетов ? Например пользователь хочет узнать, какие клиенты сделали за месяц больше 10 заявок. Это требует выполнения sql-запроса и вывода на экран пользователю в гриде. Куда впихнуть этот метод и кто его будет вызывать ?
Или например поиск всех пользователей с именем Игорь. Опять нужен метод, возвращающий DataTable с результатом sql-запроса, но где он должен находиться непонятно.
Здравствуйте, Aikin, Вы писали:
А>>Но как быть с методами отчетов ? A>Тут поможет Объект Запроса.
нет, вопрос был немного в другом. Мне не требуется составлять много разнообразных запросов на возвращение списка клиентов. Запросов всего несколько, и они будут находиться в ХП на сервере.
А мне нужны методы поиска возвращающие не коллекцию объектов, а DataTable (который в .NET), представляющий собой результат sql-запроса. Например все клиенты с именем Игорь. Должен быть возвращен набор строк, и дальше уже пользователь выберет одного из Игорей, который и будет материализован в объект Пользователь. Возможны также запросы, возвращающие какие-то аггрегированные данные и тп.
Непонятно, где эти методы должны находиться. Может создать ряд классов Отчеты ?
А>нет, вопрос был немного в другом. Мне не требуется составлять много разнообразных запросов на возвращение списка клиентов. Запросов всего несколько, и они будут находиться в ХП на сервере.
Тогда по одному (статическому) методу на каждый запрос. Куда ты эти методы засунешь -- все равно. А>А мне нужны методы поиска возвращающие не коллекцию объектов, а DataTable (который в .NET), представляющий собой результат sql-запроса.
Что-то мне не нравиться смешивание домена и чистых данных (ДатаТэйбл). Что мешает вместо дататэйбла испольовать коллекции? Коллекции отлично биндятся на любые контролы (Forms или ASP). А>Непонятно, где эти методы должны находиться. Может создать ряд классов Отчеты ?
Как вариант.
Здравствуйте, Aikin, Вы писали:
Парачку дополнений... А>>нет, вопрос был немного в другом. Мне не требуется составлять много разнообразных запросов на возвращение списка клиентов. Запросов всего несколько, и они будут находиться в ХП на сервере. A>Тогда по одному (статическому) методу на каждый запрос. Куда ты эти методы засунешь -- все равно.
Я бы засунул в специальную службу отчетов, данную проблему можно рассамтривать как проблему логирования и проверки безопасности. Данные службы out of domain так что можно не париться с их прикручиванием к домену (ничего хорошего из этого не выйдет)
А>>А мне нужны методы поиска возвращающие не коллекцию объектов, а DataTable (который в .NET), представляющий собой результат sql-запроса. A>Что-то мне не нравиться смешивание домена и чистых данных (ДатаТэйбл). Что мешает вместо дататэйбла испольовать коллекции? Коллекции отлично биндятся на любые контролы (Forms или ASP).
Aikin можно не беспокотиться об этом, так как гараздо удобнее работать с ДатаТейблом чем генерировать новые сущьности для отчетов.
А тут вам практически заменитель var из С#3.0 А>>Непонятно, где эти методы должны находиться. Может создать ряд классов Отчеты ? A>Как вариант.
Совсем недавно, решал такую проблему с одним монстроидальным проектом, обсудили с архитектором, что самый лучший вариант выделить все отчеты в отдельную сборку...
Там было написано русским по белому...
Re[4]: Domain Model, мапперы и отчеты
От:
Аноним
Дата:
20.04.08 13:50
Оценка:
Здравствуйте, Aikin, Вы писали:
A>Что-то мне не нравиться смешивание домена и чистых данных (ДатаТэйбл). Что мешает вместо дататэйбла испольовать коллекции? Коллекции отлично биндятся на любые контролы (Forms или ASP).
там есть ряд моментов. Во-первых, насколько знаю, коллекции все-таки не так уж и удобно биндить в грид — поля объекта высвечиваются в гриде в виде своего метода ToString(), а мне иногда нужно только какое-нибудь одно его поле, а не все строковое представление (ну например светим в грид объект аккаунт, который содержит параметры подключения, так вот для объекта ПараметрыПодключение мне надо не один столбец, а несколько, что-бы пользователь мог легче их просматривать и сортировать (кстати стандартный List<> вообще сортировку и фильтрацию не поддерживает, это самому похоже надо приделывать, и спрашивается нафига это делать, если куда проще взять готовый DataTable ?))
Во-вторых какой вообще смысл полученные строки превращать в объекты — на стадии поиска нужного клиента или аккаунта мне нужны только их идентификаторы. Собирание из них объектов только будет занимать время и память. А если их еще и закэшировать, так и вся оперативка забъется объектами, 99% которых в сеансе даже не потребуются.
В третьх, некоторые запросы возвращают данные, которые не относяться к существующим объектам, например суммарное количество заявок клиента за полгода. Тут и вообще никуда не деться
Вариант с другой сборкой мне нравится. А так как мы только показываем, то дататэйбл действительно хорош.
ИМХО, самое главное, чтобы не возникло желание "редактировать данные (отчеты)".
A>>Что-то мне не нравиться смешивание домена и чистых данных (ДатаТэйбл). Что мешает вместо дататэйбла испольовать коллекции? Коллекции отлично биндятся на любые контролы (Forms или ASP).
А>там есть ряд моментов. А>Во-первых, насколько знаю, коллекции все-таки не так уж и удобно биндить в грид — поля объекта высвечиваются в гриде в виде своего метода ToString(), а мне иногда нужно только какое-нибудь одно его поле, а не все строковое представление (ну например светим в грид объект аккаунт, который содержит параметры подключения, так вот для объекта ПараметрыПодключение мне надо не один столбец, а несколько, что-бы пользователь мог легче их просматривать
Не обязательно доменные объекты напрямую биндить на гриды. За пол часа можно наваять SomeObjectInfo который предоставит доступ только к нужным элементам.
А>и сортировать (кстати стандартный List<> вообще сортировку и фильтрацию не поддерживает, это самому похоже надо приделывать, и спрашивается нафига это делать, если куда проще взять готовый DataTable ?))
Сортировку по любому полю легко сделать самостоятельно (см. конец поста).
А с фильтрацией действительно траблы. Хотя ничего не стоит получать данные уже отфильтрованными (да не всегда удобно, но это "не всегда" всего 5% от всех запростов) (девекспресовский грид умеет сам фильтровать и сортировать, правда он платный, зараза).
А>Во-вторых какой вообще смысл полученные строки превращать в объекты — на стадии поиска нужного клиента или аккаунта мне нужны только их идентификаторы. Собирание из них объектов только будет занимать время и память. А если их еще и закэшировать, так и вся оперативка забъется объектами, 99% которых в сеансе даже не потребуются.
Сборка объекта не стоит ничего по сравнению с обращением к базе.
Про идентефикаторы ничего не понял
В большинстве случаем память занимаемая объектом == памяти занимаемой всеми его частями (ну может еще несколько байт, но это фигня).
Никто не говорит, что нужно забрать из базы все что касается искомого объекта. Есть Lazy Load.
А>В третьх, некоторые запросы возвращают данные, которые не относяться к существующим объектам, например суммарное количество заявок клиента за полгода. Тут и вообще никуда не деться
Действительно. Нужно обдумать эту мысль.
И все же хочу уточнить, что я не против ДатаТэйблов. Когда нужно просто посмотреть и отредактировать данные по скорости и удобству (поддержка .Net) им нет равных, но вот когда в просмотр и редактирование вкрадывается логика... Лучше сразу от них отказываться (ИМХО).
P.S.
public class GenericComparer<T> : IComparer<T>
{
private int _directionMylt = 1;
private PropertyInfo _sortPropertyInfo;
private Comparer _internalComparer = new Comparer(CultureInfo.CurrentUICulture);
public GenericComparer(string sortByProperty, SortDirection direction)
{
_sortPropertyInfo = typeof(T).GetProperty(sortByProperty);
if(_sortPropertyInfo == null)
{
throw new ArgumentException("There is no property '" + sortByProperty + "' in " + typeof(T).ToString());
}
switch (direction)
{
case SortDirection.Ascending:
_directionMylt = +1;
break;
case SortDirection.Descending:
_directionMylt = -1;
break;
}
}
private object GetValueToCompare(T instance)
{
return _sortPropertyInfo.GetValue(instance, null);
}
private int InternalCompare(T x, T y)
{
object xValue = GetValueToCompare(x);
object yValue = GetValueToCompare(y);
return _internalComparer.Compare(xValue, yValue);
}
public int Compare(T x, T y)
{
return _directionMylt * InternalCompare(x, y);
}
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1067>>
Re[6]: Domain Model, мапперы и отчеты
От:
Аноним
Дата:
21.04.08 12:32
Оценка:
Здравствуйте, Aikin, Вы писали:
A>Не обязательно доменные объекты напрямую биндить на гриды. За пол часа можно наваять SomeObjectInfo который предоставит доступ только к нужным элементам.
A>Сортировку по любому полю легко сделать самостоятельно (см. конец поста). A>А с фильтрацией действительно траблы. Хотя ничего не стоит получать данные уже отфильтрованными (да не всегда удобно, но это "не всегда" всего 5% от всех запростов) (девекспресовский грид умеет сам фильтровать и сортировать, правда он платный, зараза).
я и не спорю, что все можно сделать, просто зачем такие танцы с бубнами, когда можно и без них ?
A>Сборка объекта не стоит ничего по сравнению с обращением к базе. A>Про идентефикаторы ничего не понял A>В большинстве случаем память занимаемая объектом == памяти занимаемой всеми его частями (ну может еще несколько байт, но это фигня).
Вот смотрите, требутся пользователю найти клиента (что-бы отредактировать или что-нибудь в этом роде) — вводит в фильтр имя Игорь, и в ответ ему из БД приезжает 1000 записей с Игорями. Зачем мне материализовывать всю тысячу ? Из них он выберет только одну запись (на самом деле конечно просто введет еще одно условие фильтра, так что вся эта тысяча объектов вообще будет не нужна), которую я и превращу в объект.
Кроме того, раз уж мы потратились на материализацию, было-бы логично их закэшировать, но я думаю не стоит говорить, во что может вырасти этот кэш после дня работы.
Если-же их не кэшировать, то что-то слабо представляю, как это все будет работать — получили 1000 записей из БД, материализовали, получили смесь из новых объектов, не подлежащих кэшированию, и "старых" объектов, которые уже были в кэше. Отдали эту гремучую смесь клиенту, который возьмет и сохранит часть этих объектов. Потом он делает новый запрос к реестру, получает еще тысячу объектов, у части которых уже есть клоны ... В общем муть какая-то получается
A>Никто не говорит, что нужно забрать из базы все что касается искомого объекта. Есть Lazy Load.
кстати если не материализовывать подобные поисковые результаты, то в ряде случаев можно и без lazy load обойтись — приложение проще станет.
A>И все же хочу уточнить, что я не против ДатаТэйблов. Когда нужно просто посмотреть и отредактировать данные по скорости и удобству (поддержка .Net) им нет равных, но вот когда в просмотр и редактирование вкрадывается логика... Лучше сразу от них отказываться (ИМХО).
а ведь нету никакой особой логики-то, получили список искомых записей, выбрали нужную. Зачем нам для этого объекты ?
А>я и не спорю, что все можно сделать, просто зачем такие танцы с бубнами, когда можно и без них ?
Еще раз повторяю: если задача позволяет (нет логики в данных), то лучше DataTable я не знаю.
Вот только круг задач где к данным не примешивается логика очень узок. Для отчетов это подходит, а для изменения данных (не тупого редактирования через грид) нет.
А эти танцы делаются один раз и на все проекты сразу
A>>Сборка объекта не стоит ничего по сравнению с обращением к базе. A>>Про идентефикаторы ничего не понял A>>В большинстве случаем память занимаемая объектом == памяти занимаемой всеми его частями (ну может еще несколько байт, но это фигня). А>Вот смотрите, требутся пользователю найти клиента (что-бы отредактировать или что-нибудь в этом роде) — вводит в фильтр имя Игорь, и в ответ ему из БД приезжает 1000 записей с Игорями. Зачем мне материализовывать всю тысячу ? А>Из них он выберет только одну запись (на самом деле конечно просто введет еще одно условие фильтра, так что вся эта тысяча объектов вообще будет не нужна),
Все равно не понимаю в чем существенно в плане потребления памяти отличаются доменные объекты от дататэйбла?
Ну допустим, даже, у нас есть 20% оверхэд памяти. Неужели это так критично? И стоит поплатиться удобством программиста и ясностью кода?
С другой стороны, ты что собрался эту всю тысячу показывать? А где же пэйджинг?
А>которую я и превращу в объект.
Т.е. получается что размазываешь физическую сущность на два класса. При добавлении нового поля менять придеться два класса, у тебя будут два варианта интерфейса (один работает с таблицами, другой с объектами)...
Что-то я сомневаюсь, что поддержка такой параллельной архитектуры обоснована сомнительным выигрышем в производительности и потреблении памяти (проблем с которыми, скорее всего, нет).
А>Кроме того, раз уж мы потратились на материализацию, было-бы логично их закэшировать, но я думаю не стоит говорить, во что может вырасти этот кэш после дня работы.
Ниразу нелогично. Кэшировать нужно только то, что действительно часто вызывается. А не все подряд. Ибо проблемы с актуализацией кэша не так уж просты. (Не хочу спорить про кэш, ибо это необхватная тема).
А>Если-же их не кэшировать, то что-то слабо представляю, как это все будет работать — получили 1000 записей из БД, материализовали, получили смесь из новых объектов, не подлежащих кэшированию, и "старых" объектов, которые уже были в кэше. Отдали эту гремучую смесь клиенту, который возьмет и сохранит часть этих объектов. Потом он делает новый запрос к реестру, получает еще тысячу объектов, у части которых уже есть клоны ... В общем муть какая-то получается
Ничего не понял, но, ИМХО, ты драматизируешь.
A>>Никто не говорит, что нужно забрать из базы все что касается искомого объекта. Есть Lazy Load. А>кстати если не материализовывать подобные поисковые результаты, то в ряде случаев можно и без lazy load обойтись — приложение проще станет.
Опять "материализовать". Да эта операция занимает сотые секунды! Да нет почти никакой разницы что собирать объект или DataRow. Все одно: Get/Set/Get/Set/...
DataRow собирается автоматом, а объект нужно самому? Используй ORM движки (nHibernate, например, или LINQ to SQL от майкрософта) он все сделает за тебя.
Тем более с использованием O/R движков ты получаешь кучу фич из коробки (LazyLoad, кэш и многое другое).
A>>И все же хочу уточнить, что я не против ДатаТэйблов. Когда нужно просто посмотреть и отредактировать данные по скорости и удобству (поддержка .Net) им нет равных, но вот когда в просмотр и редактирование вкрадывается логика... Лучше сразу от них отказываться (ИМХО). А>а ведь нету никакой особой логики-то, получили список искомых записей, выбрали нужную. Зачем нам для этого объекты ?
Вот я и говорю что незачем. Для отчетов они не нужны Но это если они идут отдельной частью системы. А лучше в отдельной DLL. Чтобы не было желания добавить к ним логику: "я чуть-чуть, это будет элементарная логика".
P.S. Зарегся, плиз. Всего 5 минут, а люди будут знать с кем общаются
P.P.S. И давай на "ты", что-то меня "выканье" коробит .
Здравствуйте, Aikin, Вы писали:
A>P.S. Зарегся, плиз. Всего 5 минут, а люди будут знать с кем общаются
Done
A>Еще раз повторяю: если задача позволяет (нет логики в данных), то лучше DataTable я не знаю. A>Вот только круг задач где к данным не примешивается логика очень узок. Для отчетов это подходит, а для изменения данных (не тупого редактирования через грид) нет.
что значит логика в данных ? Я имел ввиду следующую ситуацию — пользователь хочет найти некий объект (клиента например), и что-то с ним сделать. Он вводит в фильтр имя клиента (или телефон, e-mail итп) и получает соответствующий набор строк в гриде на экране.
Далее жмет кнопку Выбрать, в результате появляется окно редактирования выбранного клиента. Понятно, что окно с редактированием будет пользоваться именно доменной моделью Клиента, а не строкой DataRow. Для этого на основе выбранной строки (идентификатора) я создам объект Клиент. А вот зачем создавать тысячу объектов Клиент на основе полученных данных для показа в гриде мне непонятно.
A>Все равно не понимаю в чем существенно в плане потребления памяти отличаются доменные объекты от дататэйбла? A>Ну допустим, даже, у нас есть 20% оверхэд памяти. Неужели это так критично? И стоит поплатиться удобством программиста и ясностью кода?
тем, что материализованные объекты нужно будет кэшировать. А набор DataRow изчезнет как только окно с ними будет закрыто (точнее когда до них уборщик мусора доберется). Так что да, для больших баз может вполне оказаться критично. Этак в течении рабочего дня вся база может плавно перетечь в оперативную память клиентской машины
Да и удобства программиста какие-то сомнительные, писать реализацию сортировки/фильтрации и разнообразные SomeObjectInfo имхо не очень удобно
A>Т.е. получается что размазываешь физическую сущность на два класса. При добавлении нового поля менять придеться два класса, у тебя будут два варианта интерфейса (один работает с таблицами, другой с объектами)... A>Что-то я сомневаюсь, что поддержка такой параллельной архитектуры обоснована сомнительным выигрышем в производительности и потреблении памяти (проблем с которыми, скорее всего, нет).
тут уже я не понял, откуда у меня 2 класса возьмется. Класс домена Клиент один. Его объект я сформирую либо прямо на основе данных в текущей строке DataRow, либо выполнив запрос к БД, используя ID клиента опять-таки текущей строки DataRow.
A>Ниразу нелогично. Кэшировать нужно только то, что действительно часто вызывается. А не все подряд. Ибо проблемы с актуализацией кэша не так уж просты. (Не хочу спорить про кэш, ибо это необхватная тема).
что значит "действительно часто вызывается" ? Как это ты определяешь-то, часто что-то вызывается, или нет ? Имхо, польза кэширования не столько в том, что-бы сэкономить обращение к БД (хотя и оно тоже конечно), сколько в том, что-бы не допустить наличия двойников одного и того-же объекта. А раз объект был материализован, значит вполне логично сложить его в кэш, что-бы разные части системы могли гарантированно работать с одной и той-же копией объекта.
A>Ничего не понял, но, ИМХО, ты драматизируешь.
ну вот смотри — обратился я к реестру объектов Клиент с запросом отдать мне всех Игорей. Вернулось 1000 игоревых объектов, причем в кэше для экономии памяти мы их не закэшировали. Я выбрал Игоря с ID = 455, и сложил куда-нибудь себе для дальнейшего пользования. Теперь я обратился к кэшу с запросом отдать мне всех клиентов, живущих в определенном районе, причем Игорь с ID = 455 тоже туда попал. Так как кэш отсутствует, то реестр мне создаст еще один объект Игорь c ID = 455. Итого я получил два разных объекта Игорь, хотя на самом деле это один и тот-же клиент.
A>Опять "материализовать". Да эта операция занимает сотые секунды! Да нет почти никакой разницы что собирать объект или DataRow. Все одно: Get/Set/Get/Set/... A>DataRow собирается автоматом, а объект нужно самому? Используй ORM движки (nHibernate, например, или LINQ to SQL от майкрософта) он все сделает за тебя. A>Тем более с использованием O/R движков ты получаешь кучу фич из коробки (LazyLoad, кэш и многое другое).
я вообщем-то не особо спорю с тем, что создать объекты можно быстро. Как я уже написал, основные проблемы в другом месте. Но тем не менее обрати внимание, что помимо сотых долей секунды, для этого также потребуется собственно реализация разнообразных сортировок/фильтраций и SomeObjectInfo, что усложняет систему на совершенно ровном месте.
S>Далее жмет кнопку Выбрать, в результате появляется окно редактирования выбранного клиента. Понятно, что окно с редактированием будет пользоваться именно доменной моделью Клиента, а не строкой DataRow. Для этого на основе выбранной строки (идентификатора) я создам объект Клиент. А вот зачем создавать тысячу объектов Клиент на основе полученных данных для показа в гриде мне непонятно.
Для меня нет большой разницы между DataRow и Client (из домена) и тот и тот будет требовать примерно одинаковое количество ресурсов. Разница только в том, что к Client можно добавить логику, а к DataRow нет.
S>тем, что материализованные объекты нужно будет кэшировать. А набор DataRow изчезнет как только окно с ними будет закрыто (точнее когда до них уборщик мусора доберется). Так что да, для больших баз может вполне оказаться критично. Этак в течении рабочего дня вся база может плавно перетечь в оперативную память клиентской машины
Да брось ты с этим кэшированием. Зачем? Ну и что что у нас будет два разных объекта представляющие одного клиента, кто тебе сказал, что это конец света?
Что мешает переорпеделить Equals() чтобы при сравнении программа знала что это один и тот же объект?
Отработавшие же объекты так же оставляются на съедение гарбидж коллектору.
S>Да и удобства программиста какие-то сомнительные, писать реализацию сортировки/фильтрации и разнообразные SomeObjectInfo имхо не очень удобно
А удобно на каждый чих создавать свой собственный типизированный DataTable? Или, может, дататэйблы у тебя вообще нетипизированные?
S>тут уже я не понял, откуда у меня 2 класса возьмется. Класс домена Клиент один. Его объект я сформирую либо прямо на основе данных в текущей строке DataRow, либо выполнив запрос к БД, используя ID клиента опять-таки текущей строки DataRow.
Один класс DataRow, второй -- Client.
S>что значит "действительно часто вызывается" ? Как это ты определяешь-то, часто что-то вызывается, или нет ? Имхо, польза кэширования не столько в том, что-бы сэкономить обращение к БД (хотя и оно тоже конечно), сколько в том, что-бы не допустить наличия двойников одного и того-же объекта. А раз объект был материализован, значит вполне логично сложить его в кэш, что-бы разные части системы могли гарантированно работать с одной и той-же копией объекта.
В моем понятии кэш это когда мы что-то храним чтобы не обращаться лишний раз к БД (например). А то про что ты говоришь это Identity Map.
См выше. про Equals()
S>Так как кэш отсутствует, то реестр мне создаст еще один объект Игорь c ID = 455. Итого я получил два разных объекта Игорь, хотя на самом деле это один и тот-же клиент.
См выше. про Equals() Который чаще всего использует ID для сравнения.
S>я вообщем-то не особо спорю с тем, что создать объекты можно быстро. Как я уже написал, основные проблемы в другом месте. Но тем не менее обрати внимание, что помимо сотых долей секунды, для этого также потребуется собственно реализация разнообразных сортировок/фильтраций и SomeObjectInfo, что усложняет систему на совершенно ровном месте.
Да будет так. Не хочешь -- не используй. У меня нет достаточного прокаченного скила "красноречие" чтобы тебя убедить
В общем советую просмотреть код проекта сделанного на NHibernate (советую тут (Enterprise NHibernate Sample) просмотри DAO и Domain все остальное это ASP .net на MVP), ИМХО, просто, понятно и действительно меньше лишних телодвижений.
Здравствуйте, Aikin, Вы писали:
A>Да брось ты с этим кэшированием. Зачем? Ну и что что у нас будет два разных объекта представляющие одного клиента, кто тебе сказал, что это конец света? A>Что мешает переорпеделить Equals() чтобы при сравнении программа знала что это один и тот же объект?
Зачем ? Хм, могу предложить ситуацию из моего реального проекта. Система по учету производства деталей. Имеется набор деталей, каждая из них имеет технологию производства, причем одна и та-же технология может быть задействована в нескольких деталях. Пользователь загружает набор деталей для просмотра. Разумеется, время от времени в одном наборе деталей оказываются детали с одинаковой технологией.
А теперь смотри — пользователь отредактировал технологию детали А. Потом переключился на деталь Б, имеющую эту-же технологию. Но из-за того, что деталь Б имеет другой объект Технология (хоть и с одним ID), он увидит старую неотредактированную технологию.
Может это и не конец света, но очевидно баг программы. И никакие Equals() здесь не помогут
A>А удобно на каждый чих создавать свой собственный типизированный DataTable?
ну не на каждый чих, а на каждую таблицу с результатами поиска
A>Один класс DataRow, второй -- Client.
а причем здесь тогда размазывание сущности по двум классам и интерфейсам
A>В моем понятии кэш это когда мы что-то храним чтобы не обращаться лишний раз к БД (например). А то про что ты говоришь это Identity Map. A>См выше. про Equals()
в моем понятии кэш сочетает в себе все эти достоинства.
A>В общем советую просмотреть код проекта сделанного на NHibernate (советую тут (Enterprise NHibernate Sample) просмотри DAO и Domain все остальное это ASP .net на MVP), ИМХО, просто, понятно и действительно меньше лишних телодвижений.
к сожалению хибернейт не умеет маппить объекты на хранимые процедуры, в результате чего мы его не применяем. Вот Microsoft обещают сделать маппинг на ХП
S>Зачем ? Хм, могу предложить ситуацию из моего реального проекта. Система по учету производства деталей. Имеется набор деталей, каждая из них имеет технологию производства, причем одна и та-же технология может быть задействована в нескольких деталях. Пользователь загружает набор деталей для просмотра. Разумеется, время от времени в одном наборе деталей оказываются детали с одинаковой технологией. S>А теперь смотри — пользователь отредактировал технологию детали А. Потом переключился на деталь Б, имеющую эту-же технологию. Но из-за того, что деталь Б имеет другой объект Технология (хоть и с одним ID), он увидит старую неотредактированную технологию. S>Может это и не конец света, но очевидно баг программы. И никакие Equals() здесь не помогут
1) Пользователь получил этот набор в одной бизнес транзакции? Тогда ничего не стоит (и это будет много проще чем кэш живущий все время приложения) сделать чтобы одинаковые сущности представлялись одинаковыми классами.
Тем более Идентити Мап гарантирует уникальность только в пределах одной бизнес транзакции: "An Identity Map keeps a record of all objects that have been read from the database in a single business transaction." (статья выше).
Этот паттерн дается за фри при использовании nHibernate
2) В разных?
Тогда в любом случае стоит перегрузить эти данные, так как их может изменить кто-то другой.
A>>А удобно на каждый чих создавать свой собственный типизированный DataTable? S>ну не на каждый чих, а на каждую таблицу с результатами поиска
То же самое про SomeObjectInfo. Причем тут даже не на каждый результат поиска, а на каждый резултат, что мы будем показывать пользователю.
A>>Один класс DataRow, второй -- Client. S>а причем здесь тогда размазывание сущности по двум классам и интерфейсам
Ну как же: "если мы просто показываем данные как результат запроса, то используем DataRow, а если манипулируем ими, то Client".
Про интерфейсы я ни словом
A>>В моем понятии кэш это когда мы что-то храним чтобы не обращаться лишний раз к БД (например). А то про что ты говоришь это Identity Map. A>>См выше. про Equals() S>в моем понятии кэш сочетает в себе все эти достоинства.
Лучше их все таки разделить. А то непонятно что конкретно имеешь ввиду Я вот не сразу понял, что ты про Идентети Мап (в моем понимании).
S>к сожалению хибернейт не умеет маппить объекты на хранимые процедуры, в результате чего мы его не применяем. Вот Microsoft обещают сделать маппинг на ХП
Ниразуниправда
В документации: 13.2.2. Using stored procedures for querying
Здравствуйте, Aikin, Вы писали:
A>1) Пользователь получил этот набор в одной бизнес транзакции? Тогда ничего не стоит (и это будет много проще чем кэш живущий все время приложения) сделать чтобы одинаковые сущности представлялись одинаковыми классами. A>Тем более Идентити Мап гарантирует уникальность только в пределах одной бизнес транзакции: "An Identity Map keeps a record of all objects that have been read from the database in a single business transaction." (статья выше). A>Этот паттерн дается за фри при использовании nHibernate
A>2) В разных? A>Тогда в любом случае стоит перегрузить эти данные, так как их может изменить кто-то другой.
это вообще говоря смотря что называть бизнес-транзакцией В любом случае, для ситуаций типа "загруженные данные может изменить кто-то другой" имеется оптимистическая блокировка и кнопка "Обновить данные" на экране. А иначе просто потеряется весь смысл кэширования, если ты будешь перечитывать все данные для каждой так называемой "бизнес-транзакции".
A>То же самое про SomeObjectInfo. Причем тут даже не на каждый результат поиска, а на каждый резултат, что мы будем показывать пользователю.
(+ реализация сортировки/фильтрации)Что-то мне не кажется, что это сильно одинаковые по затратам веши тем более, если уж пошла такая пьянка, чем принципиально твой SomeObjectInfo лучше DataRow ? Он ведь тоже к доменной модели особого отношения иметь не будет
A>Ну как же: "если мы просто показываем данные как результат запроса, то используем DataRow, а если манипулируем ими, то Client".
не, там у тебя было что-то про дублирование изменений в обоих классах и прочее В датароу я ведь ничего дублировать не буду, просто заберу выбранный ID'шник и пойду с ним в БД
A>>>В моем понятии кэш это когда мы что-то храним чтобы не обращаться лишний раз к БД (например). А то про что ты говоришь это Identity Map. A>>>См выше. про Equals()
раз уж ты так любишь точные названия паттернов, то как называется паттерн, который просто занимается кэшированием ? Что-то я такого у Фаулера не нашел. Да и вообще странный какой-то кэш получается, не гарантирует мне возвращение одного и того-же объекта
A>Ниразуниправда A>В документации: 13.2.2. Using stored procedures for querying
действительно, не знал, а когда это там появилось ? А ленивая загрузка (на ХП) и оптимистическое блокирование тоже в нем есть ?
S>это вообще говоря смотря что называть бизнес-транзакцией В любом случае, для ситуаций типа "загруженные данные может изменить кто-то другой" имеется оптимистическая блокировка и кнопка "Обновить данные" на экране. А иначе просто потеряется весь смысл кэширования, если ты будешь перечитывать все данные для каждой так называемой "бизнес-транзакции".
Пусть будет так.
S>(+ реализация сортировки/фильтрации)Что-то мне не кажется, что это сильно одинаковые по затратам веши тем более, если уж пошла такая пьянка, чем принципиально твой SomeObjectInfo лучше DataRow ? Он ведь тоже к доменной модели особого отношения иметь не будет
Принципиальная разница в том, что: SomeObjectInfo это класс представления (UI), который использует слой домена в совей основе, а DataRow это класс доступа к данным который использует слой доступа к данным минуя домен.
A>>Ну как же: "если мы просто показываем данные как результат запроса, то используем DataRow, а если манипулируем ими, то Client". S>не, там у тебя было что-то про дублирование изменений в обоих классах и прочее В датароу я ведь ничего дублировать не буду, просто заберу выбранный ID'шник и пойду с ним в БД
Не знаю что ты понял с моих слов, но имел ввиду я именно "если мы просто показываем данные как результат запроса, то используем DataRow, а если манипулируем ими, то Client"
S>раз уж ты так любишь точные названия паттернов, то как называется паттерн, который просто занимается кэшированием ? Что-то я такого у Фаулера не нашел. Да и вообще странный какой-то кэш получается, не гарантирует мне возвращение одного и того-же объекта
Как ни странно "кэш" Но давай не будет об этом спорить
S>действительно, не знал, а когда это там появилось ? А ленивая загрузка (на ХП) и оптимистическое блокирование тоже в нем есть ?
Недавно в 1.2 версии. А хз Я их не пользовал.
Что-то наша дискуссия перестала нести конструктивный характер (постов 5 назад), а больше похоже на перебранку.
Так что предлагаю закончить с ней
Здравствуйте, Aikin, Вы писали:
A>Что-то наша дискуссия перестала нести конструктивный характер (постов 5 назад), а больше похоже на перебранку. A>Так что предлагаю закончить с ней
OK
Re[15]: Эх бы я действительно по пивку рубанул бы!!!!!!!!!
Добавлю своих 5-ть копеек, так как читаю данную ветку...
S>>это вообще говоря смотря что называть бизнес-транзакцией В любом случае, для ситуаций типа "загруженные данные может изменить кто-то другой" имеется оптимистическая блокировка и кнопка "Обновить данные" на экране. А иначе просто потеряется весь смысл кэширования, если ты будешь перечитывать все данные для каждой так называемой "бизнес-транзакции". A>Пусть будет так.
Позволю не согласиться со Stalker'ом, так как кэширование может быть на любом уровне, хотите на уровне БД, на уровне транзакции, на уровне всего приложения или на уровне клиента.
А вот смысл такого кэширования, можно будет увидить только в определенном контексте.
A>Принципиальная разница в том, что: SomeObjectInfo это класс представления (UI), который использует слой домена в совей основе, а DataRow это класс доступа к данным который использует слой доступа к данным минуя домен.
Aikin вы пытаетель подменить некоторые понятия. Задача Stalker стояла в получении данных из БД и построение по ним отчетов.
Так вот если использовать someObjectInfo, то если его применять необходимо будет:
— либо использовать доменные объекты, которые придется преобразовывать к someObjectInfo.
— либо на основе DataRow формировать someObjectInfo.
Есть ли смысл городить такой огород?
Я считаю что в большенстве случаев необходимость в это отсутствует.
S>>раз уж ты так любишь точные названия паттернов, то как называется паттерн, который просто занимается кэшированием ? Что-то я такого у Фаулера не нашел. Да и вообще странный какой-то кэш получается, не гарантирует мне возвращение одного и того-же объекта A>Как ни странно "кэш" Но давай не будет об этом спорить
Как раз Identity Map и отвечает за возращение одного и того-же объекта. А вот кэширование это эффект, которые порождает необходимость возврата одного и того-же экземпляра
CRA>Aikin вы пытаетель подменить некоторые понятия. Задача Stalker стояла в получении данных из БД и построение по ним отчетов. CRA>Так вот если использовать someObjectInfo, то если его применять необходимо будет: CRA>- либо использовать доменные объекты, которые придется преобразовывать к someObjectInfo. CRA>- либо на основе DataRow формировать someObjectInfo. CRA>Есть ли смысл городить такой огород? CRA>Я считаю что в большенстве случаев необходимость в это отсутствует.
Да я уже n (n > 5) постов назад сказал что для отчетов DataRow рулез, вот только Stalker настаивает на том, что данные нужно сначала показать пользователю а уже потом создавать из них доменные объекты и манипулировать ими.
S>>>раз уж ты так любишь точные названия паттернов, то как называется паттерн, который просто занимается кэшированием ? Что-то я такого у Фаулера не нашел. Да и вообще странный какой-то кэш получается, не гарантирует мне возвращение одного и того-же объекта A>>Как ни странно "кэш" Но давай не будет об этом спорить CRA>Как раз Identity Map и отвечает за возращение одного и того-же объекта. А вот кэширование это эффект, которые порождает необходимость возврата одного и того-же экземпляра
А я что против?
S>>>Да и вообще странный какой-то кэш получается, не гарантирует мне возвращение одного и того-же объекта
Не заметил что-то я этой фразы.
Кэш вообще ничего не гарантирует. Его функция заключается в сокращении количества обращений к ресурсам требующим время: удаленный доступ, сложные вычисления, ... Причем он не может гарантировать что нужный объект будет в кэше.
Вполне может быть такая ситуация когда кэш вернет два разных объекта представляющих одну и ту же сущность:
1) Доступ к объекту User (id = 27)
2) Кэш его вернула
3, 4, ..., 89) Ты работаешь с этим юзером, делаешь тяжелую работу, съел кучу памяти, ..., на кэш напал GC (гарбидж коллектор), съел половину объектов, в том числе и наш объект User (id = 27)
90) Тебе опять понадобился этот юзер, ты его запрашиваешь, кэш понимает что у нее этого юзера нет -- лезет в базу и создавет новый объект
А если не отдавать коллектору ничего в кэше, то скоро в него, действительно, перетечет вся база данных