Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> hibernate пометить поле удалённым, но не удалять физически 
V
    Опции темы
Samotnik
Дата 30.4.2011, 15:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Super star !
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 7192
Регистрация: 4.11.2006
Где: Минск City

Репутация: 5
Всего: 191



Привет smile
Есть приложение работающее с БД через хибер. Нужно, при удалении записей не удалять их физически из БД, а помечать как удаленные, для того чтобы в последующем, можно было делать запросы на удалённые записи.
Сделал это так: добавил в таблицы поле boolean deleted, по дефолту оно false, как только запись удаляется, я сеччу в это поле null, таким образом я избегаю unique constraint violated эксепшена, выглядит это так:
Код

@Entity
@Table(uniqueConstraints=@UniqueConstraint(columnNames={"name", "deleted"}))
public class Test { 
@Id
private long id;

@Column(nullable = false)
private String name;

private Boolean deleted = false;

//остальные поля
}


Всё отлично работало с MySQL, в БД спокойно ложились записи вида:
('test1', null)
('test1', null)
('test1', null)
('test1', null)
и т.д. 

Но вот беда, перешёл на Oracle, а там это не прокатывает, получается что там null == null если этот null в состовном ключе находится, и как следствие вылетает constraint violated эксепшен. 

Вопрос, что можно придумать в данной не простой ситуации, что можете подсказать или посоветовать smile  smile 
Как вариант, можно попробовать использовать envers, но может другие решения есть ?


Это сообщение отредактировал(а) Samotnik - 30.4.2011, 15:54
PM MAIL   Вверх
Старовъръ
Дата 30.4.2011, 16:01 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 491
Регистрация: 8.5.2008

Репутация: 1
Всего: 10



Зачем нужны Unique constraints на deleted?
PM MAIL WWW   Вверх
carper
Дата 3.5.2011, 08:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 227
Регистрация: 2.3.2005

Репутация: 2
Всего: 8



Цитата(Samotnik @  30.4.2011,  15:50 Найти цитируемый пост)
 только запись удаляется, я сеччу в это поле null


Null, строго говоря, не следует использовать как флаг, т.к. null - означает неопределенное состояние.

Поле - метка удаленной записи не должно нести на себе каких-то уникальных констрейнов, как вам сказал Старовъръ.

В сухом остатке - создайте boolean field named as DELETED default false, при удалении заносите туда true, а не null.
И поле не должно быть частью первичного ключа!
PM MAIL   Вверх
Samotnik
Дата 3.5.2011, 18:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Super star !
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 7192
Регистрация: 4.11.2006
Где: Минск City

Репутация: 5
Всего: 191



Цитата(carper @  3.5.2011,  08:18 Найти цитируемый пост)
В сухом остатке - создайте boolean field named as DELETED default false, при удалении заносите туда true, а не null.
И поле не должно быть частью первичного ключа! 

Да, но как быть с уникальностью поля name в таком случае ? Их не должно быть более одного одинакового, если оно не помечено как deleted.

Добавлено через 12 минут и 30 секунд
Цитата(Старовъръ @  30.4.2011,  16:01 Найти цитируемый пост)
Зачем нужны Unique constraints на deleted? 

потому что в БД, не может быть создано более одного имени Nikolai, но удалено их может быть сколько угодно. Если не создать uniqueConstraints на поля "name", "deleted", то как по-другому уникальность реализовать ?

Это сообщение отредактировал(а) Samotnik - 3.5.2011, 18:48
PM MAIL   Вверх
Старовъръ
Дата 3.5.2011, 21:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 491
Регистрация: 8.5.2008

Репутация: 1
Всего: 10



Ну тогда располагай хотя бы true/false, а не true/null. Ну или в таком случае введи понятие версии, а не флажка. Если мы удалили или что-то изменили, то создается новая версия объекта с таким же ID и с инкременченной версией. Или может имеет смысл это хранить в каком-то архивном хранилище дабы не снижать производительность БД.

Это сообщение отредактировал(а) Старовъръ - 3.5.2011, 22:03
PM MAIL WWW   Вверх
Samotnik
Дата 4.5.2011, 00:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Super star !
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 7192
Регистрация: 4.11.2006
Где: Минск City

Репутация: 5
Всего: 191



Старовъръ,  т.е. использовать envers ?

Это сообщение отредактировал(а) Samotnik - 4.5.2011, 00:33
PM MAIL   Вверх
carper
Дата 4.5.2011, 09:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 227
Регистрация: 2.3.2005

Репутация: 2
Всего: 8



Цитата(Samotnik @  3.5.2011,  18:48 Найти цитируемый пост)
Да, но как быть с уникальностью поля name в таком случае ? Их не должно быть более одного одинакового, если оно не помечено как deleted.


Введите ограничение на то, что поле name просто должно быть уникальным, независимо от того есть ли такое поле помеченное как "удаленное" или нет.  Т.к. иначе вы получаете сразу два Васи, отличающихся только тем, что один из них помечен как удаленный - спрашивается и какой из 2-х Васей в таком случае помечен?

Более того, поскольку у вас запись только помечена как удаленная, это автоматически предполагает, что вы можете передумать, тогда совсем уж глупо иметь двух Васей, отличающихся только признаком удаленной записи.

Я, кстати, вообще подозреваю, что вы на самом деле хотите запись помечать не как удаленную, а как скрытую, или неактуальную, предполагая, что с прежним Васей что-то связано.

У вас 100% проблемы не с пометкой полей, а с архитектурой. В частности с первичными ключами.



P.S.
И причем тут  envers?  Вам таки нужна версионность и куча записей в архиве на каждого удаленного Васю?
Во-первых, это просто делается и без envers - просто введите соотв. поле, во-вторых, версионность для одного и того же Васи, скажем для адресов его проживания, совсем не одно и тоже, что и версионность для ряда совсем разных Вась, в последнем случае, это вообще чушь какая-то получится.  smile


P.P.S.
И наличие синтетического первичного ключа по ID в большинстве случаев совсем не освобождает от необходимости "человекопонимаемого" АК.


PM MAIL   Вверх
MisterCleric
Дата 4.5.2011, 10:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1043
Регистрация: 16.2.2006
Где: Харьков, Украина

Репутация: 33
Всего: 38



Привет всем.
Я делаю так:
При пометке записи как удаленная в те поля, которые должны быть уникальны, к существующему значению добавляю метку времени, а также проставляю статус как удаленная. 
Таким образом поле всегда уникально, избавляемся от композитный констрейнтов и ключей. А также такие записи всегда можно отфильтровать по like.
Естественно, что у меня заведомо длина поля больше чем, я предоставляю для ввода пользователем...


--------------------
ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ...
PM MAIL ICQ   Вверх
Samotnik
Дата 4.5.2011, 11:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Super star !
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 7192
Регистрация: 4.11.2006
Где: Минск City

Репутация: 5
Всего: 191



Цитата(MisterCleric @  4.5.2011,  10:59 Найти цитируемый пост)
При пометке записи как удаленная в те поля, которые должны быть уникальны, к существующему значению добавляю метку времени, а также проставляю статус как удаленная. 
Таким образом поле всегда уникально, избавляемся от композитный констрейнтов и ключей.

не понимаю, как это можно сделать без композитных ключей ? Ведь поле name должно быть само по себе уникально, т.е. что бы пользователь не смог вставить запись Dima дважды  smile 
Поясни плиз. 
И вот это я совсем не понял:
Цитата(MisterCleric @  4.5.2011,  10:59 Найти цитируемый пост)
Естественно, что у меня заведомо длина поля больше чем, я предоставляю для ввода пользователем... 


PM MAIL   Вверх
MisterCleric
Дата 4.5.2011, 11:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1043
Регистрация: 16.2.2006
Где: Харьков, Украина

Репутация: 33
Всего: 38



Поясню на примере:
1. Было у нас в записи значение поля name Вася.
2. Я помечаю эту запись как удаленную.
3. Апдейчу поле name приблизительно так: 
Код

user.name += ' [' + new Date().time + ']


Благодаря тому, что время всегда идет вперед, пользователь никогда не сможет нарушить уникальность

Добавлено через 2 минуты и 10 секунд
И насчет композитный ключей: у тебя должно быть поле ID с генерируемым числовым значением - автоинкремент, сиквенс, или что там у тебя поддерживает БД


--------------------
ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ...
PM MAIL ICQ   Вверх
Samotnik
Дата 4.5.2011, 12:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Super star !
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 7192
Регистрация: 4.11.2006
Где: Минск City

Репутация: 5
Всего: 191



MisterCleric, прикольно, эванокак smile 
А чем хуже, если объединить name и deleteTimeStamp в UniqueConstraint ? Вроде ж тоже уникальность будет. 

Цитата(MisterCleric @  4.5.2011,  11:52 Найти цитируемый пост)
И насчет композитный ключей: у тебя должно быть поле ID с генерируемым числовым значением - автоинкремент, сиквенс, или что там у тебя поддерживает БД 

С Id тут вообще целая история, он у меня вот так генерится:
Код

@Id
@GenericGenerator(name="customIdGenerator", strategy="CustomIdGenerator")
@GeneratedValue(strategy=GenerationType.TABLE, generator="customIdGenerator")
private long id;


где
Код

public class CustomIdGenerator extends TableGenerator {
    
    private static final Log logger = LogFactory.getLog(CustomIdGenerator.class);

    @Override
    public Serializable generate(SessionImplementor session, Object object)
            throws HibernateException {
        long id;
        try {
            id = (Long)object.getClass().getMethod("getId").invoke(object);
        } catch (Throwable t) {
            logger.fatal(t, t);
            return super.generate(session, object);
        }
        if (id > 0) {
            return id;
        } else {
            return super.generate(session, object);
        }
    }
}

Вроде так работает и для MySQL и для Oracle
PM MAIL   Вверх
MisterCleric
Дата 4.5.2011, 12:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1043
Регистрация: 16.2.2006
Где: Харьков, Украина

Репутация: 33
Всего: 38



Цитата

А чем хуже, если объединить name и deleteTimeStamp в UniqueConstraint ? Вроде ж тоже уникальность будет. 


Можно и так, но какое тогда у тебя будет там значение у "неудаленных" записей?
Ведь уже обсудили, что NULL не нормально использовать в уникальных констрейнтах

Добавлено через 1 минуту и 10 секунд
И по твоему генератору.
Какая тогда проблема?
Ведь поле name у тебя не участвует в PK записи.


--------------------
ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ...
PM MAIL ICQ   Вверх
Samotnik
Дата 4.5.2011, 13:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Super star !
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 7192
Регистрация: 4.11.2006
Где: Минск City

Репутация: 5
Всего: 191



MisterCleric, ясно. А что делать, если есть сущности в которых уже есть композитные ключи, например:
Код

@Table(uniqueConstraints=@UniqueConstraint(columnNames={"subscriber_id", "message_id"}))
public class Delivery {

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="message_id")
    private Message message;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="subscriber_id")
    private Subscriber subscriber;
//....
}

Как в таком случае ее помечать удалённой ?

Это сообщение отредактировал(а) Samotnik - 4.5.2011, 13:10
PM MAIL   Вверх
MisterCleric
Дата 4.5.2011, 14:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1043
Регистрация: 16.2.2006
Где: Харьков, Украина

Репутация: 33
Всего: 38



Но у тебя же здесь композитный ключ состоит из внешних ключей.
На что у тебя здесь идет уникальность? Где то бизнес-поле, которое требует уникальности?
У тебя же такая конкретна сущность относится к конкретным внешним сущностям. Если ты их помечаешь как удаленные эта тоже должна быть таковой.
Или у тебя эти внешние ключи неуникальны?


--------------------
ПРИШЕЛ, УВИДЕЛ - ПЕРЕПИСАЛ...
PM MAIL ICQ   Вверх
Samotnik
Дата 4.5.2011, 14:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Super star !
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 7192
Регистрация: 4.11.2006
Где: Минск City

Репутация: 5
Всего: 191



MisterCleric, да, всё верно, спасибо, должно работать. 
Еще вопрос, генерить hashCode() и equals() лучше всего по id или uniqueConstraints или id + uniqueConstraints 
 smile 
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.0973 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.