Ссылочная целостность с одним к одному, используя спящий режим - PullRequest
3 голосов
/ 22 марта 2011

У меня две таблицы -

Foo {foo_id, name}
Foo_properties {fp_id, foo_id, phoneNumber}

Теперь я хочу отобразить это в моей объектной модели, используяhibernate .. Мне нужен foo_id в Foo_properties, потому что я хочу сохранить ссылочную целостность и хочу добавить ограничение ON DELETE CASCADE.
, поэтому я отобразил отношение следующим образом -

@Entity
public class Foo{
    @Id
    private long foo_id;

    private String name;

    @OneToOne(mappedBy = "foo")
    private FooProperties fooProperties;
}

@Entity
public class FooProperties{

    @Id
    private long fp_id;

    private String phoneNumber;

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

Теперь, поскольку владельцем является класс FooProperties, я сталкиваюсь со следующими проблемами:

Если я установлюновый экземпляр FooProperties для Foo, существующие FooProperties все еще остаются в БД, и hibernate не удаляет этот экземпляр, например,

Foo foo = entityManager.find(Foo.class, fooId);
foo.setFooProperties(new FooProperties("xxx-xxx-xxx"));
entityManager.merge(foo);

В результате получается новая строка в таблице FooProperties вместе с существующей,Теперь я не понимаю, как я могу изменить свое отображение так, чтобы вышеупомянутый код (или его вариант) работал для всех сценариев, что означает, что мне нужен Foo как сторона-владелец и foo_id в FooProperties.Есть ли способ определить сопоставление следующим образом?

ПРИМЕЧАНИЕ. Я уже задавал вопрос , основываясь на этом, но я думаю, что в предыдущем вопросе мне было непонятно, поэтому задал еще один.

Ответы [ 4 ]

4 голосов
/ 22 марта 2011

Вам уже сказали использовать orphanRemoval = true или CascadeType.DELETE_ORPHAN.Однако из-за казуистики в интерпретации спецификации JPA она не будет работать должным образом для отношений один-к-одному ( HHH-5559 ).

Вы можете добиться правильного поведения orphanRemoval со следующим трюком:

@Entity
public class Foo{
    @OneToMany(mappedBy = "foo", orphanRemoval = true)
    private List<FooProperties> fooProperties;

    public FooProperties getFooProperties() {
        if (fooProperties == null || fooProperties.isEmpty()) return null;
        else return fooProperties.get(0);
    }

    public void setFooProperties(FooProperties newFooProperties) {
        if (fooProperties == null) fooProperties = new ArrayList<FooProperties>();
        else fooProperties.clear();
        if (newFooProperties != null)
            fooProperties.add(newFooProperties);            
    }
    ...
}

@Entity
public class FooProperties{
    @ManyToOne
    @JoinColumn(name = "foo_id",  nullable = false)
    private Foo foo;
    ...
}

Или даже это, если вам не нужно FooPropeties.foo:

@Entity
public class Foo{
    @OneToMany(orphanRemoval = true)
    @JoinColumn(name = "foo_id",  nullable = false)        
    private List<FooProperties> fooProperties;

    // getter/setter as above
    ...
}
2 голосов
/ 22 марта 2011

Я думаю, что вместо вызова слияния для сущности, если вы напрямую вызовете update для объекта сеанса , то hibernate сначала удалит существующую строку, а затем добавит новую. Я реализовал то же самое, но в моем случае я использовал xml для отображения сущности. Я надеюсь, что это поможет вам.

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

Есть 2 варианта на выбор, поскольку вы не хотите менять отображение:

  1. Сделайте это с помощью логики вашего сервисного уровня. Я думаю, что у вас уже есть похожий вопрос.
  2. Используйте аннотацию Hibernate @Cascade (org.hibernate.annotations.CascadeType.DELETE_ORPHAN) на стороне Foo отношения. Однако это явно Hibenate и JPA 2 не включает в себя поддержку того же самого.
0 голосов
/ 18 марта 2011

Bar является владельцем ассоциации (как указано mappedBy на обратной стороне), и поэтому там должен быть установлен каскад.

Edit:

Чтобы инвертировать это, это может помочь.

...