![]() |
Модераторы: LSD, AntonSaburov |
![]() ![]() ![]() |
|
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
Привет
![]() Есть приложение работающее с БД через хибер. Нужно, при удалении записей не удалять их физически из БД, а помечать как удаленные, для того чтобы в последующем, можно было делать запросы на удалённые записи. Сделал это так: добавил в таблицы поле boolean deleted, по дефолту оно false, как только запись удаляется, я сеччу в это поле null, таким образом я избегаю unique constraint violated эксепшена, выглядит это так:
Всё отлично работало с MySQL, в БД спокойно ложились записи вида: ('test1', null) ('test1', null) ('test1', null) ('test1', null) и т.д. Но вот беда, перешёл на Oracle, а там это не прокатывает, получается что там null == null если этот null в состовном ключе находится, и как следствие вылетает constraint violated эксепшен. Вопрос, что можно придумать в данной не простой ситуации, что можете подсказать или посоветовать ![]() ![]() Как вариант, можно попробовать использовать envers, но может другие решения есть ? Это сообщение отредактировал(а) Samotnik - 30.4.2011, 15:54 |
|||
|
||||
Старовъръ |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 491 Регистрация: 8.5.2008 Репутация: 1 Всего: 10 |
Зачем нужны Unique constraints на deleted?
-------------------- |
|||
|
||||
carper |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 227 Регистрация: 2.3.2005 Репутация: 2 Всего: 8 |
Null, строго говоря, не следует использовать как флаг, т.к. null - означает неопределенное состояние. Поле - метка удаленной записи не должно нести на себе каких-то уникальных констрейнов, как вам сказал Старовъръ. В сухом остатке - создайте boolean field named as DELETED default false, при удалении заносите туда true, а не null. И поле не должно быть частью первичного ключа! |
|||
|
||||
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
Да, но как быть с уникальностью поля name в таком случае ? Их не должно быть более одного одинакового, если оно не помечено как deleted. Добавлено через 12 минут и 30 секунд потому что в БД, не может быть создано более одного имени Nikolai, но удалено их может быть сколько угодно. Если не создать uniqueConstraints на поля "name", "deleted", то как по-другому уникальность реализовать ? Это сообщение отредактировал(а) Samotnik - 3.5.2011, 18:48 |
|||
|
||||
Старовъръ |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 491 Регистрация: 8.5.2008 Репутация: 1 Всего: 10 |
Ну тогда располагай хотя бы true/false, а не true/null. Ну или в таком случае введи понятие версии, а не флажка. Если мы удалили или что-то изменили, то создается новая версия объекта с таким же ID и с инкременченной версией. Или может имеет смысл это хранить в каком-то архивном хранилище дабы не снижать производительность БД.
Это сообщение отредактировал(а) Старовъръ - 3.5.2011, 22:03 -------------------- |
|||
|
||||
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
||||
|
||||
carper |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 227 Регистрация: 2.3.2005 Репутация: 2 Всего: 8 |
Введите ограничение на то, что поле name просто должно быть уникальным, независимо от того есть ли такое поле помеченное как "удаленное" или нет. Т.к. иначе вы получаете сразу два Васи, отличающихся только тем, что один из них помечен как удаленный - спрашивается и какой из 2-х Васей в таком случае помечен? Более того, поскольку у вас запись только помечена как удаленная, это автоматически предполагает, что вы можете передумать, тогда совсем уж глупо иметь двух Васей, отличающихся только признаком удаленной записи. Я, кстати, вообще подозреваю, что вы на самом деле хотите запись помечать не как удаленную, а как скрытую, или неактуальную, предполагая, что с прежним Васей что-то связано. У вас 100% проблемы не с пометкой полей, а с архитектурой. В частности с первичными ключами. P.S. И причем тут envers? Вам таки нужна версионность и куча записей в архиве на каждого удаленного Васю? Во-первых, это просто делается и без envers - просто введите соотв. поле, во-вторых, версионность для одного и того же Васи, скажем для адресов его проживания, совсем не одно и тоже, что и версионность для ряда совсем разных Вась, в последнем случае, это вообще чушь какая-то получится. ![]() P.P.S. И наличие синтетического первичного ключа по ID в большинстве случаев совсем не освобождает от необходимости "человекопонимаемого" АК. |
|||
|
||||
MisterCleric |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1043 Регистрация: 16.2.2006 Где: Харьков, Украина Репутация: 33 Всего: 38 |
Привет всем.
Я делаю так: При пометке записи как удаленная в те поля, которые должны быть уникальны, к существующему значению добавляю метку времени, а также проставляю статус как удаленная. Таким образом поле всегда уникально, избавляемся от композитный констрейнтов и ключей. А также такие записи всегда можно отфильтровать по like. Естественно, что у меня заведомо длина поля больше чем, я предоставляю для ввода пользователем... -------------------- ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ... |
|||
|
||||
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
не понимаю, как это можно сделать без композитных ключей ? Ведь поле name должно быть само по себе уникально, т.е. что бы пользователь не смог вставить запись Dima дважды ![]() Поясни плиз. И вот это я совсем не понял:
|
|||
|
||||
MisterCleric |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1043 Регистрация: 16.2.2006 Где: Харьков, Украина Репутация: 33 Всего: 38 |
Поясню на примере:
1. Было у нас в записи значение поля name Вася. 2. Я помечаю эту запись как удаленную. 3. Апдейчу поле name приблизительно так:
Благодаря тому, что время всегда идет вперед, пользователь никогда не сможет нарушить уникальность Добавлено через 2 минуты и 10 секунд И насчет композитный ключей: у тебя должно быть поле ID с генерируемым числовым значением - автоинкремент, сиквенс, или что там у тебя поддерживает БД -------------------- ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ... |
|||
|
||||
Samotnik |
|
||||||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
MisterCleric, прикольно, эванокак
![]() А чем хуже, если объединить name и deleteTimeStamp в UniqueConstraint ? Вроде ж тоже уникальность будет.
С Id тут вообще целая история, он у меня вот так генерится:
где
Вроде так работает и для MySQL и для Oracle |
||||||
|
|||||||
MisterCleric |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1043 Регистрация: 16.2.2006 Где: Харьков, Украина Репутация: 33 Всего: 38 |
Можно и так, но какое тогда у тебя будет там значение у "неудаленных" записей? Ведь уже обсудили, что NULL не нормально использовать в уникальных констрейнтах Добавлено через 1 минуту и 10 секунд И по твоему генератору. Какая тогда проблема? Ведь поле name у тебя не участвует в PK записи. -------------------- ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ... |
|||
|
||||
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
MisterCleric, ясно. А что делать, если есть сущности в которых уже есть композитные ключи, например:
Как в таком случае ее помечать удалённой ? Это сообщение отредактировал(а) Samotnik - 4.5.2011, 13:10 |
|||
|
||||
MisterCleric |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1043 Регистрация: 16.2.2006 Где: Харьков, Украина Репутация: 33 Всего: 38 |
Но у тебя же здесь композитный ключ состоит из внешних ключей.
На что у тебя здесь идет уникальность? Где то бизнес-поле, которое требует уникальности? У тебя же такая конкретна сущность относится к конкретным внешним сущностям. Если ты их помечаешь как удаленные эта тоже должна быть таковой. Или у тебя эти внешние ключи неуникальны? -------------------- ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ... |
|||
|
||||
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
MisterCleric, да, всё верно, спасибо, должно работать.
Еще вопрос, генерить hashCode() и equals() лучше всего по id или uniqueConstraints или id + uniqueConstraints ![]() |
|||
|
||||
MisterCleric |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1043 Регистрация: 16.2.2006 Где: Харьков, Украина Репутация: 33 Всего: 38 |
Вообще советуют по какому-нибудь бизнес-ключу.
В твоем случае, наверное, uniqueConstraint достаточно. Но это, конечно, если оно у тебя всегда заполнено -------------------- ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ... |
|||
|
||||
Samotnik |
|
||||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
MisterCleric, понял, спасибо. На счет сущностей, которые связывают другие, всё же способ не работает:
Создаю запись: id, device_id, app_id, deleted (1; 5; 9; false) Удаляю (1; 5; 9; true) Создаю опять точно такую же - (2; 5; 9; false)
![]() Это сообщение отредактировал(а) Samotnik - 4.5.2011, 16:53 |
||||
|
|||||
MisterCleric |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1043 Регистрация: 16.2.2006 Где: Харьков, Украина Репутация: 33 Всего: 38 |
Не понял. Почему "Создаю такую же"?
Ведь это же новая запись: должен быть id новый. Что у тебя за бардак такой? -------------------- ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ... |
|||
|
||||
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
MisterCleric, да, извини не дописал, уже исправил, id конечно же новый. Но при чем он тут ? У меня уникальность стоит по полям device_id + app_id именно по этому я не могу создать нового subscriber если уже существует такой же удалённый.
Это сообщение отредактировал(а) Samotnik - 4.5.2011, 16:59 |
|||
|
||||
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
почему бардак ![]() Вот представь, очень простой пример. Тебе дали задание разработать сущность "Пользователь" с двумя полями Имя, Фамилия. При условии, что нельзя создать двух одинаковых записей с одной именем + фамилией(например нельзя создать Дмитрий Петров дважды ![]() Плюс предусмотреть сохранение удалённых пользователей, т.е. не удалять их физически из БД, а каким-либо образом помечать что они удалены и не мешали созданию новых полей (и их удаление) Т.е. БД должна себя вести, как будто этих записей нету в таблице. Это я релизовал с помощью флага deleted, путем выставления его в null при удалении записи. С MySQL всё превосходно работало, а вот с Oracle нет. |
|||
|
||||
MisterCleric |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1043 Регистрация: 16.2.2006 Где: Харьков, Украина Репутация: 33 Всего: 38 |
Тогда добавь к этой уникальности еще и ID.
Или вообще убери эту уникальность на внешние ключи. Не понимаю ее смысла. У тебя что по логике нельзя создать несколько Subscriber на один и тот же Device в одном и том же App? Да и вообще самый идеальный вариант - провести нормализацию: удаленные записи переносить в архивные таблицы. -------------------- ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ... |
|||
|
||||
Samotnik |
|
||||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
не вариант, тогда можно будет создавать Дмитрий Петров сколько угодно раз. смысл в том, чтобы запретить создавать более одной записи Дмитрий Петров
а это как ? ![]()
нет, нельзя, а какой смысл создавать их несколько ? Зачем столько записей ? Подписчик должен быть один. id, device_id, app_id, deleted (1; 5; 9) (2; 5; 9) (3; 5; 9) (4; 5; 9) (5; 5; 9) (6; 5; 9) .... Это сообщение отредактировал(а) Samotnik - 4.5.2011, 17:57 |
||||
|
|||||
MisterCleric |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1043 Регистрация: 16.2.2006 Где: Харьков, Украина Репутация: 33 Всего: 38 |
Не знаю таких ссылок, но на пальцах это так:
1. Копия оригинальной таблицы с префиксом ARC 2. Убираем констрейнты, окромя PK 3. Вызываем обычное удаление 4. В БД на удаление должен быть триггер на каждую таблицу 5. Он должен просто взять удаляемую запись и проинсертить в соответствующую архивную таблицу. 6. Потом ты сможешь эти записи доставать через named-query, а результат повесить на твою основную сущность. Польза: разделяем данные по логике, повышается производительность на основной таблице. Минусы: много работы на БД, написание named-query на удаленные записи. Нужно здесь хорошенько подумать, стоит ли все данные оставлять: может будет нормальным, если какие-то связи все-таки будут удаляться навсегда? -------------------- ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ... |
|||
|
||||
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
||||
|
||||
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
Если кому интересно, то проблема решилась как всегда - очень просто.
Поле deleted - сделать типом long по дефолту = -1L, при удалении сетить в это поле тот id, который удаляется ![]() Добавлено через 6 минут и 7 секунд
так может тогда лучше по id ? |
|||
|
||||
MisterCleric |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1043 Регистрация: 16.2.2006 Где: Харьков, Украина Репутация: 33 Всего: 38 |
Привет. Решение красивое.
Сам додумался? Век живи - век учись... По поводу equals & hashCode. У меня вот такой вот класс для всех сущностей:
Я, кажись, его тут уже на форуме выкладывал. Он хорошо работает в рамках логики, которую пишу я. Но для самого Hibernate оно не годиться, так как тот у себя в коде использует класс org.hibernate.util.IdentityMap, который для hashCode вызывает System.identityHashCode, а для equals еще хуже - идет сравнение ссылок. -------------------- ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ... |
|||
|
||||
Samotnik |
|
|||
![]() Super star ! ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 7192 Регистрация: 4.11.2006 Где: Минск City Репутация: 5 Всего: 191 |
спс
|
|||
|
||||
![]() ![]() ![]() |
Правила форума "Java" | |
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |