Вопрос по Hibernate
От: Jeremy Россия  
Дата: 16.12.10 09:21
Оценка:
Всем привет.

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

Итак есть сущности A, B, C. Ссылаются они друг на друга вот так: A -> B -> C. Хранятся соответственно в трех таблицах.

Есть метод обьекта, который где-то внутри открытой транзакции пытается загрузить обьект A (и соответственно связанные с ним B и C) по его идентификатору. В штатном режиме все работает отлично. Но вот возникла ситуация, когда в цепочке A -> B -> C отсутствует последний элемент, то есть в таблице С нет записи с идентификатором указанным в таблице B. При этом бросается "org.hibernate.ObjectNotFoundException", что есть правильно. Однако с точки зрения логики моей программы эта ошибка не должна приводить к фатальным последствиям, то есть я ее ловлю, пишу в лог и продолжаю работать дальше. И вот здесь возникает проблема. При попытке закоммитить транзакцию бросается новая ошибка типа "org.hibernate.HibernateException: Found two representations of same...". Анализ стектрейса показывает, что происходит эта беда при session.flush() что случается перед коммитом транзакции. Причем в сессии я вижу висящим
обьект A загрузка которого вызвала ошибку №1 (и попытка сохранить который приводит к ошибке №2).

Вопрос такой — почему вообще обьект А оказался в сессии — ведь он не был до конца загружен, то есть по идее находится в невалидном состоянии? Как с этим бороться?
Re: Вопрос по Hibernate
От: Blazkowicz Россия  
Дата: 16.12.10 09:27
Оценка:
Здравствуйте, Jeremy, Вы писали:

J>Но вот возникла ситуация, когда в цепочке A -> B -> C отсутствует последний элемент, то есть в таблице С нет записи с идентификатором указанным в таблице B. При этом бросается "org.hibernate.ObjectNotFoundException", что есть правильно. Однако с точки зрения логики моей программы эта ошибка не должна приводить к фатальным последствиям,

У вас целостность базы нарушена и это не должно приводить к фатальным последствиям??? Почему констрейнта на FK нет?

J>то есть я ее ловлю, пишу в лог и продолжаю работать дальше. И вот здесь возникает проблема. При попытке закоммитить транзакцию бросается новая ошибка типа "org.hibernate.HibernateException: Found two representations of same...". Анализ стектрейса показывает, что происходит эта беда при session.flush() что случается перед коммитом транзакции. Причем в сессии я вижу висящим

J>обьект A загрузка которого вызвала ошибку №1 (и попытка сохранить который приводит к ошибке №2).
J>Вопрос такой — почему вообще обьект А оказался в сессии — ведь он не был до конца загружен, то есть по идее находится в невалидном состоянии? Как с этим бороться?
Хотелось бы все же увидеть полный текст ошибки, stacktrace и немного кода. Ибо ошибка Found two representations of same collection у меня с вашим A-B-C что-то не вяжется.
Re: Вопрос по Hibernate
От: GarryIV  
Дата: 16.12.10 09:30
Оценка: +1
Здравствуйте, Jeremy, Вы писали:

J>Вопрос такой — почему вообще обьект А оказался в сессии — ведь он не был до конца загружен, то есть по идее находится в невалидном состоянии? Как с этим бороться?


Потому, что никто не обещал, что сессия хибернейта будет находится в рабочем состоянии после исключения.
WBR, Igor Evgrafov
Re[2]: Вопрос по Hibernate
От: Jeremy Россия  
Дата: 17.12.10 08:18
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>У вас целостность базы нарушена и это не должно приводить к фатальным последствиям??? Почему констрейнта на FK нет?


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

B>Хотелось бы все же увидеть полный текст ошибки, stacktrace и немного кода. Ибо ошибка Found two representations of same collection у меня с вашим A-B-C что-то не вяжется.


Код (синтетический пример), сорри за обьем:

1. Описание сущностей:


    @Entity
    @Table(name="A")
    public static class A {

        private String id;
        private List<B> children;

        public A(){}

        @Column(name = "id")
        @Id
        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        @OneToMany(mappedBy="parentId", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
        public List<B> getChildren() {
            return children;
        }

        public void setChildren(List<B> children) {
            this.children = children;
        }
    }

    @Entity
    @Table(name="A1")
    public static class B {

        private String id;
        private String parentId;
        private C child;

        public B(){
        }

        @Column(name = "id")
        @Id
        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        @Column(name = "parentid")
        public String getParentId() {
            return parentId;
        }

        public void setParentId(String parentId) {
            this.parentId = parentId;
        }

        @OneToOne(fetch = FetchType.EAGER)
        @JoinColumn(name="ID", referencedColumnName="ID", insertable = false, updatable = false)
        public C getChild() {
            return child;
        }

        public void setChild(C child) {
            this.child = child;
        }
    }

    @Entity
    @Table(name = "A2")
    public static class C {

        private String id;

        public C() {
        }

        @Column(name = "id")
        @Id
        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }
    }


2. Считывание экземпляра A:


    public A getA(String id){
        return (A) factory.getCurrentSession()
                .createCriteria(A.class)
                .add(Restrictions.eq("id", id))
                .uniqueResult();
    }


3. Фрагмент кода, бросающий исключение:


        Transaction t = factory.getCurrentSession().beginTransaction();
        try {
            try{
                getA("1");
            } catch (Exception ex){
                 // Здесь ловим org.hibernate.ObjectNotFoundException: No row with the given identifier exists
                        }
            t.commit();
        } catch(Exception e){
            // Здесь ловим исключение, описанное в п.4
        }


4. Стектрейс:

org.hibernate.HibernateException: Found two representations of same collection: A.children
    at org.hibernate.engine.Collections.processReachableCollection(Collections.java:153)
    at org.hibernate.event.def.FlushVisitor.processCollection(FlushVisitor.java:37)
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101)
    at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61)
    at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55)
    at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:138)
    at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:196)
    at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
Re[3]: Вопрос по Hibernate
От: Blazkowicz Россия  
Дата: 17.12.10 08:43
Оценка: 1 (1)
Здравствуйте, Jeremy, Вы писали:

@org.hibernate.annotations.NotFound(action=NotFoundAction.IGNORE)
Re[4]: Вопрос по Hibernate
От: Jeremy Россия  
Дата: 17.12.10 09:02
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>@org.hibernate.annotations.NotFound(action=NotFoundAction.IGNORE)


Да, я в курсе . Скорее всего, по этому пути и придется идти.

Два момента:

1. Изначально так не сделал поскольку мне все-таки хотелось отслеживать случаи с несуществующим экземпляром C и, как минимум, логировать их появления. В случае с ловлей исключения это было сделать проще. В случае использования @NotFound придется вводить дополнительную проверку на NULL, руками фильтровать результаты, что кмк сделает код менее понятным.

2. Все-таки любопытно разобраться в причинах такого поведения Hibernate. Мне оно кажется крайне нелогичным. Не смог загрузить обьект (ObjectNotFound) — зачем при этом портить всю сессию, делая невозможной дальнейшую работу?
Re[5]: Вопрос по Hibernate
От: Blazkowicz Россия  
Дата: 17.12.10 09:09
Оценка:
Здравствуйте, Jeremy, Вы писали:

J>2. Все-таки любопытно разобраться в причинах такого поведения Hibernate. Мне оно кажется крайне нелогичным. Не смог загрузить обьект (ObjectNotFound) — зачем при этом портить всю сессию, делая невозможной дальнейшую работу?

Откуда все же берется вторая коллекция? Посмотрите содержимое сессии в дебаге.
Re[5]: Вопрос по Hibernate
От: Blazkowicz Россия  
Дата: 17.12.10 09:12
Оценка:
Здравствуйте, Jeremy, Вы писали:

J>2. Все-таки любопытно разобраться в причинах такого поведения Hibernate. Мне оно кажется крайне нелогичным. Не смог загрузить обьект (ObjectNotFound) — зачем при этом портить всю сессию, делая невозможной дальнейшую работу?

Может попробовать на самой последней версии Hibernate?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.