[JAVA]Hibernate O/R без уникального primary key
Задача возникла из соображений версионности, если это кому-нить поможет...
попробуй composite-id, если уж нет выделенного ключа
Primary key есть всегда, надо только его выделить.
Композитный ключ тоже не подходит, потому что инфа о версии хранится в виде пары дат (время действия версии и поэтому пара ид+нач. дата хоть и будет идентифицировать объект, но выборку по ней делать абсолютно бесполезно...
Так что тут либо добавочную колонку, либо... либо хрен его знает что!
Я новичок в Хибернэйте, так что советы и поучения - велкам очень дажэ!
У тебя проблемы не с Hibernate, а с моделью данных. В реляционной модели любая запись имеет ключ. Вырожденный случай - когда ключом являются все поля записи (объекта). Попробуй сам проанализировать.
Вполне возможно. Тогда что ты можешь посоветовать для реализации версионности объектов? Какую модель данных? Модель, которой хочу воспользоваться я (см. выше) была использована в одной достаточно крупной системе, которая работатет и продается уже не первый год. Там, правда, без Hibernate написано все было, на Oracle Forms (ну PL/SQL короче и все просто ок было. Вот я и решил перенести этот подход на свой проект.
+ простота (не надо больше гемороиться)
+ при выборке быстрее будет сравнить 2 int-а чем что-то, состоящее из нескольких колонок
- занимает лишнее место
id -- id идентификатор (non-unique)
fd -- timestamp дата начала действия версии
td -- timestamp дата окончания действия версии
.
.
при выборке запросы типа where id=? and fd<date and td>date для получения версии на дату date. Куда здесь еще один инт совать? И с чем его сравнивать?
я пока сделал так- добавил еще одну колонку с уник. ид, а все выборки делаю не учитывая эту колонку, т.е. она нужна только для внутренних целей хибернейта.
Может, я не прав в модели данных? Поправьте, если кто может.
Так у тебя версионность одной сущности или нескольких?
в таблице лежит набор версий для набора объектов
а что такое сущность в твоем понимании?
я несколько в терминах еще путаюсь, так что...
Короче ты ведешь разговор про одну-единственную таблицу?
Идея в чем - при изменении данных объекта мы не меняем его запись, а открываем новую версию, т.е. на последней версии время "по" ставим текущим и вставляем новую запись с тем же ид объекта и соотв временами действия.
между несколькими таблицами такого рода вполне можно делать связи, при этом выборка (в терминах sql) делается примерно так:
select ... from tbl1, tbl2 where tbl2.master=tbl1.id and tbl2.fd<date and tbl2.td>date and tbl1.fd<date and tbl1.td>date
тут, как видно мы берем данные из 2ух таблиц, актуальные на дату date
вообще, это, как я понимаю, не единственный способ реализации версионности, но я видел только такую реализацию, придумывать новую нет времени, однако, если ты сможешь подсказать какой-нить другой подход - я с удовольствием его рассмотрю и возможно применю
основная задача - возможность посмотреть состояние системы на любой момент времени.
версию выделяем в отдельную таблицу, например, VERSION, с числовым идентификатором версии. fd/td суть атрибуты версии. Далее, каждый объект в качестве одного из атрибутов первичного ключа имеет номер версии. Чтобы попасть в какой-то период времени, надо сначала узнать нужный номер версии. Чтобы вытащить объект, надо знать его идентификатор и номер версии.
Недостатки очевидны - не может быть объектов, покрывающих сразу несколько версий. Переход к следующей версии усложняется. Зато - полная определенность с доступом к объекту.
а... понял... но запросы на выборку усложнятся серьезно в этом случае, а как следствие и время выборок. Так как система будет достаточно большой, это критично...
Насколько я помню, hibernate поддерживает кастом запросы для поиска объекта по ключу (в твоем случае для hibernate`а имхо ключом будет пара id, date, а то, что один и тот же объект можно получить по разным парам id, date - не его, хибернейта, собачье дело).
Но все это цветочки, а вот подумай, что будет, если между объектами есть отношения, т.е. references. Как в этом случае поведет себя база, предсказать не берусь
В его модели можно за какой-то период получить сразу два объекта
как, если не секрет?
для ссылочных объектов я выше приводил пример запроса
На такой версионности построена одна из очень известных биллинговых систем, кстати, так что модель эта то что называется, проверена в полевых условиях. Просто появилось желание прикрутить Hibernate к проекту, вот и маюсь.
Да, но какое это имеет отношение к primary key?
А второе замечание я вообще не понял
2. Допустим, объект A ссылается на объект B. Как выглядит внешний ключ объекта B? На какую конкретно версию объекта B ссылается объект A?
3. Биллинговые системы - плохой пример нормализации, там все сделано из соображений performance.
id, fd, td и будет primary key
если я прально понял, то один и тот же объект не может иметь две версии с пересекающимися промежутками "жизни", так что это будет не primary key а unique просто...
а primary будет минимум 2 - id,td id,fd
а касаемо версий - имхо для версий вести отдельную таблицу, а в основной хранить только текущую версию
+ плюс ввести поле "номер версии"
ЗЫ это все касаемо модели данных...
а хибернэйт ваш я не рюхаю
2. Допустим, объект A ссылается на объект B. Как выглядит внешний ключ объекта B? На какую конкретно версию объекта B ссылается объект AСсылка идет не на конкретную версию, а на сам объект. При выборке данных берется версия, актуальная на заданую дату. Я ж приводил пример запроса выше.
Ну да, по идее {id, from, to} будет ключом записи. Только выборка по такому ключу лишена смысла в силу того, что выборки делаются (ну по большому счету) по 2ум параметрам - id объекта и дате. Что-то типа
id=? and fd<? and td>? в where части запроса стоит
Далее про ссылки. Как ты будешь делать версионный join? Допустим, в одной из таблиц, которым ты делаешь join, за указанный период нет ни одной записи, что тогда? Как ты собираешься поддерживать корректность дат всей этой связки объектов (таблиц)?
Как это нет такой гарантии? Гарантия есть, она в бизнес-логике реализуется.
Так зачем тебе тогда Hibernate, если у тебя все в бизнес-логике реализуется?
Допустим, объект A ссылается на объект B. Как выглядит внешний ключ объекта B?
В реляционной модели "ссылки" реализуется не всегда через внешние ключи. Вообще, в основном внешние ключи используются СУБД для поддержания целостности БД, прямого (теоретического) отношения к "связям" они не имеют. Просто, в часто распространенной ситуации, когда нет бизнес-правил, соответствующих 4-ой и 5-ой нормальным формам, связь по внешнему ключу используется для навигации (например, ADO.Net).
Если в рассматриваемом примере бизнес-правило таково, что любая версия A ссылается на объект B, то это случай 4-й нормальной формы и внешнего ключа не построишь.
Вопрос автора треда я не совсем понял (я не знаком с хивернейт ) . Если первичные и внешние ключи используются для навигации как Ralation в DataSet.Net, то, да, такого Relation не построишь, придется делать select. (хотя может и построишь )
P.S для поддержания правила целостности -- объект B не может существовать без объекта A) -- имхо, придется писать триггер (или забить на него ).
В реляционной модели "ссылки" реализуется не всегда через внешние ключи. Вообще, в основном внешние ключи используются СУБД для поддержания целостности БД, прямого (теоретического) отношения к "связям" они не имеют.
Оба-на. А как же реализуются ссылки в реляционной модели?
теоретически ссылок в рел. модели вообще нет, данные выбираются с помощью реляционной алгебры
правильно. а в реляционной алгебре есть операция соединения, которая, в частности, сопоставляет внешний ключ с первичным.
соединение можно делать по любым полям, они не обязатнльно должны быть первичным и внешним ключом, вообщем, об этом я и говорил выше
а вообще это злостный оффтопик
имхо, нет
тогда опиши мне как ты в этой модели будешь делать взаимосвязанные версионные объекты
надо уточнить, словосочетание "объект A ссылается на B", как оно звучит, когда у объектов есть версии?
вот когда ты ответишь на этот вопрос, вскроются все недостатки решения с этими from/to
Если бизнес-правило таково, что одна версия A ссылается на одну версию B, то будут две таблицы (id_a, date_a, ..... (id_b, date_b, id_a, date_a, ....... в принципе можно убрать столбец date_a из второй таблицы, но тогда нельзя будет построить внешний ключ и поддерживать ограничение целостности, и в запросах придется явно указывать дату.
Если бизнес-правила другие, то и таблицы, возможно, будут другими.
P.S. date_a и date_b это даты начала версии, вводить в первичный ключ даты окончания нехорошо, поскольку можно разрешить им принимать значение null
from/to
Версия объекта ссылаться ни на кого не может. Ссылаться может объект И не на версию другого объекта, а на сам другой объект.
from/to это даты начала и окончания жизни версии объекта
В запросах дату и так надо явно указывать в этой модели.
с джойнить по двум полям и всё. Указывать явно, я имел ввиду, указывать значение даты типа '01/01/2002' или типа того
ааа, ну вот и мудохайтесь со своими "объектами" и "ссылается", пока вы сами не поймете, что под этими словами вы имеете ввиду и не объясните другим, у вас так и будут возникать проблемы. В реальности ни объектов ни ссылок не существует.
Мы в свое время делали систему, где реально поддерживалась версионность деревьев объектов как на уровне компонентов (отношений часть-целое так и на уровне произвольных связей типа один-ко-многим. Писали месяца два как минимум. Я это к тому, что задача сама по себе совершенно недетская.
Оставить комментарий
puare
Отцы! Никто не в курсе, как можно сабж реализовать?