Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > hibernate пометить запись удаленной


Автор: Samotnik 14.10.2010, 12:31
Привет.
Нужно реализовать САБЖ. Т.е. при удалении не удалять поле, а просто выставлять некий boolean флаг в true(что означает, что запись удалена)
т.е. порще говоря, в методе для удаления я вместо привычного session.delete(object) вызываю просто сеттер для флага, т.е. object.setRemove(true)
Вроде все хорошо smile Но появилась проблема - в этой таблице присутствует поле из другой таблицы, которые связаны связью.
Вот таблица (Men), в которой присутствует поле из другой таблицы (Device)

Код

public class Men {
        @Id
    @Column(unique = true, nullable = false)
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "device_id")
    private Device device; 

//..... 

А вот маппинг Device
Код

public class Device {
    @Id
    @Column(unique = true, nullable = false)
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;

    @OneToMany(mappedBy = "device", cascade = {CascadeType.REMOVE}, fetch = FetchType.EAGER)
    private Set<Men> men;


Получается, что при удалении device, у меня не явно удаляется и men, а я хочу этого избежать. Мне нельзя удалять men физически, а просто помечать что он удален.
Какой есть выход из положения ? 

Автор: carper 14.10.2010, 16:53
Samotnik
Если в таблице men есть ссылка на поле из таблицы device, то удалить данные из device, оставив висящую ссылку на это поле в men можно только если делать поле device_id в men необязательным и писать туда null.

Но тогда получается, что удаление из таблицы device не стоит описывать через CascadeType.REMOVE (не говоря уж о том, что во многих СУБД это гораздо проще и логичней задается еще на этапе создания таблиц), а надо написать соотв. триггер/процедуру в базе, либо производить удаление в java методе, которые и позаботятся о замене device_id на null и пометке записи.

Hibernate не настолько умен, чтобы автоматически догадаться о вашей хитрой операции.
Для этого, и тысячи других, случаев и пишутся классы, реализующие DAO, которые и занимаются особенностями CRUD.

У вас вообще какой-то странный случай, когда таблица men как-бы настолько зависит от device, что записи в ней должны помечаться как удаленные, а с другой удаляться не должны.
Нет, приблизительно о целях догадаться можно, но обычно для этого существуют более "правильные" способы. 

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

Автор: Samotnik 14.10.2010, 18:07
Цитата(carper @  14.10.2010,  16:53 Найти цитируемый пост)
я стараюсь вообще избегать автоматического каскадного удаления

Эти слова уже не первый человек говорит. Неужели все так плохо. smile

Тут идея вся в чем. 
Есть таблица (людей) которые подписываются на новость, и в этой таблице есть поле, которое приходит из другой таблицы по связи (пример я уже давал). Есть возможность добавления/удаления/редактирования людей. Но удалять не хочется, потому что нужно оставить для статитстики, например, кто за пол года удалился, присоединился, и в какое время. А если тупо удалять, после того как человек отписывается, то статитиски никакой не будет. А это плохо.

Автор: carper 15.10.2010, 08:34
Samotnik,
Вы бы тогда пояснили, что лежит в device_id и какой объем информации предполагается хранить в men, а то с ходу придумывается сразу два решения - денормализация men по device_id или отдельная таблица для статистики, опять же, или совсем без device_id или с денормализованным значением.


"Эти слова уже не первый человек говорит. Неужели все так плохо."

Ну как вам сказать, это все равно как спор нужен ли нормальный генератор экранных форм в JAVA?

Для quick and dirty решений несомненно нужен и очень обидно, что сообщество JAVA долгое время почему-то полагало совсем иначе, да и сейчас не все так гладко, по крайней мере те генераторы, что  я видел (а видел я их мало, так что, возможно, не прав) хуже чем в Delphi 2.

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

Опять же, для большинства нормальных СУБД для каскадного удаления Hibernate и нафиг не нужен.

В Hibernate вообще часть решений связана с тем чтобы обеспечить универсальность в тех областях, которые на практике нужны 0,01% разработчиков, да и тем неясно зачем.

Например, Oracle, Ms SQL, DB2, MySQL (InnoDB), Firebird, Interbase, PostgreSQ, Apach Derby, Cloudscape, думаю при желании можно вспомнить еще десяток, поддерживают ON DELETE CASCADE "из коробки", причем это решение принимается на этапе создания архитектуры и для этого не надо загаживать JAVA код не нужными аннотациями.

Hibernate хорош там, где надо отобразить плоские реляционные таблицы на объекты, во всем остальном для проектов всерьез использующих работу с СУБД, надо быть очень осторожным, полагаясь на его услуги, но могут оказаться медвежьими. smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)