Проблема слияния в спящем режиме с отображением один на один - PullRequest
1 голос
/ 16 марта 2011

У меня есть иерархия классов, сопоставленная с InheritanceType.JOINED в Hibernate (финал 3.5.6) с JPA 2.0 -

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class A{
    private Long id;

    @OneToOne
    @JoinColumn(name = "foo_id",  nullable = false)
    private Foo foo;
    ...
}

@Entity
@PrimaryKeyJoinColumn(name = "B_ID")
public class B{
        ...
}

@Entity
@PrimaryKeyJoinColumn(name = "C_ID")
public class C{
        ...
}

А Foo сущность -

@Entity
public class Foo{
    @Id
    private Long id;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "foo")
    private A a

    // getters / setters omitted    
}

Теперь я сохранил сущность Foo со ссылкой B в поле 'a'. Позже я хотел бы обновить экземпляр Foo со ссылкой на класс C до свойства 'a', так что я сделал -

loadedFooInstance.setA(new C());
entityManager.merge(loadedFooInstance);

Но то, что я заметил, - он не удаляет исходный объект B, который был назначен этому объекту Foo, перед назначением C. Из-за этого мне нужно вручную удалить всю ссылку A, назначенную этому экземпляру Foo перед назначением нового.
Но я считаю, что hibernate должен иметь возможность справляться с такими сценариями, и я что-то упускаю в своем отображении. Что-то не так в моем отображении ... или такое отображение может быть достигнуто лучшим способом, поэтому мне не нужно заниматься такой ручной работой.

Ответы [ 2 ]

0 голосов
/ 16 марта 2011

Что-то здесь не так в этой схеме.Когда вы удаляете B, вы хотите удалить Foo, следовательно, A является владельцем отношения.Таким образом, без существования B, Foo не должно существовать.Но то, что вы делаете сейчас, это удаление B из Foo, следовательно, нарушая отношения, так как теперь нет B. Вы должны следовать совету Ральфа # 2.Совет № 1 будет работать нормально, но ясно, что Foo должен быть владельцем.И каскадирование также будет работать с отображенной стороны.Ваши определенные отношения не верны.

РЕДАКТИРОВАТЬ:

Чтобы установить существующий B в Foo на C: Это почти похоже на более ранний Совет Ральфа # 1

Foo foo = entityManager.find(Foo.class, id);
B b = foo.getA();
entityManager.remove(b); //Explicitly remove or B still remains in database as B is the owning side
C c = new C();
c.setFoo(foo);
entityManager.persist(c);  //c is the owning side, hence save c and not foo
entityManager.refresh(foo);
0 голосов
/ 16 марта 2011

Ваш корабль OneToOne Relation управляется стороной A, а не стороной Foo. Таким образом, вам нужно изменить отношения на стороне A (потому что Hibernate обращает только внимание на сторону, где отношения управляются)

A old = loadedFooInstance.getA();
oldA.setFoo(null);
C c = new C();
c.setFoo(loadedFooInstance);
/*and it is good practic to update foo too*/
loadedFooInstance.setA(c);

Другой способ - изменить сторону, управляющую отношениями:

public abstract class A{
   ...
   @OneToOne(mappedBy = "a") 
   private Foo foo;
   ...
}

public class Foo{
    ...
    @OneToOne
    @JoinColumn(name = "a_id",  nullable = false)
    private A a
    ...
 }

Но это также изменит структуру вашей базы данных!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...