2009-12-08 3 views
5

Я хочу однонаправленный Индивидуальные отношения между объектами из 3 классов java: от человека к сердцу и лица к печени. Я хочу, чтобы объекты имели один и тот же ПК, то есть каждый человек имеет соответствующее сердце и печень, где person.person_id = heart.heart_id = liver.liver_id. Я не хочу объединять 3 таблицы в 1, потому что у каждого есть множество полей. Вот мой код (в основном на основе принятого ответа на this question):Hibernate взаимно-однозначная ассоциация с общим PK между 3 классами

@Entity 
public class Person { 
    public long personId; 
    private String name; 
    public Heart heart; 
    public Liver liver; 
    // other fields 

    @Id 
    @GeneratedValue 
    public long getPersonId() {return personId;} 

    @OneToOne(cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    public Heart getHeart() {return heart;} 

    @OneToOne(cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    public Liver getLiver() {return liver;} 

    // other getters and setters and constructors 
} 


@Entity 
public class Heart { 
    private long heartId; 
    private int bpm; 
    private Person person; 
    // other fields 

    @Id 
    @GenericGenerator(
     name = "generator", 
     strategy = "foreign", 
     parameters = @Parameter(name = "property", value = "person") 
    ) 
    @GeneratedValue(generator = "generator") 
    public long getHeartId() {return heardId;} 

    @OneToOne(mappedBy="heart") 
    @PrimaryKeyJoinColumn 
    public Person getPerson() {return person;} 

    // other getters and setters and constructors 
} 


@Entity 
public class Liver { 
    private long liverId; 
    private boolean healthy; 
    private Person person; 
    // other fields 

    // the rest uses the same hibernate annotation as Heart 
} 

I Настройка сеанса и выполните следующие действия:

Person jack = new Person(); 
jack.setName("jack"); 
Heart heart = new Heart(); 
heart.setBpm(80); 
Liver liver = new Liver(); 
liver.setHealthy(true); 

Тогда, если я связываю объект человека с его органами, и сохранить его, я получаю сообщение об ошибке (Примечание: я получил такое же поведение, когда я только что использовали 2 классов, например, Человек и сердце):

jack.setHeart(heart); 
jack.setLiver(liver); 
session.save(jack); 

орг. hibernate.id.IdentifierGenerationException: попытка присвоить идентификатор из нулевой собственности один-к-одному: человек

Однако это работает, если я установить взаимосвязи в обоих направлениях:

jack.setHeart(heart); 
heart.setPerson(jack); 
jack.setLiver(liver); 
liver.setPerson(jack); 
session.save(jack); 

Но, конечно, это не должно быть необходимо для однонаправленных отношений?
Cheers

ps. Как ни странно, я замечаю, что он работает (сохраняет оба объекта в БД), когда я просто использую 2 класса, например. Человек и сердце, и я просто установить связь по-другому:

heart.setPerson(jack); 
session.save(heart); 

Я понятия не имею, почему это работает (кажется логичным, что лицо является родительским объектом, так как он автоматически генерирует свой собственный ПК, и другие используют это, так что это все, что вам нужно настроить), но в любом случае я не могу понять, как применить этот рабочий метод к моей ситуации в 3 классах ...

+0

Я только что нашел этот вопрос, который я думаю о той же ситуации, но использует совершенно иной подход (он использует @Embeddable и @Inheritance): http://stackoverflow.com/questions/ 904634. Единственная проблема заключается в том, что в принятом решении недостаточно кода, чтобы понять/реализовать его ... может ли кто-нибудь помочь? – jackocnr

ответ

6

Ненавижу говорить вам это, но у вас есть двунаправленные отношения. У человека есть ссылка на Сердце и Печень, и у каждого из них есть ссылка на Человека. Аннотации, которые вы настроили на свойствах идентификатора вашего сердца и печени, специально говорят о том, что они получают ценность своего свойства Id, делегируя их свой собственный объект.В примерах, которые вы показали, что не работают, вы еще не установили свойство Person у этих ребят и так, они, очевидно, не могут получить свое значение Id.

Вы можете установить эту связь в качестве истинного однонаправленного OneToOne, которая документально в аннотациями документации Hibernate:

@Entity 
public class Body { 
    @Id 
    public Long getId() { return id; } 

    @OneToOne(cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    public Heart getHeart() { 
     return heart; 
    } 
    ... 
} 


@Entity 
public class Heart { 
    @Id 
    public Long getId() { ...} 
} 

или вы можете изменить нашу сущность объектов немного упростить подключение с обеих сторон отношений такие как:

@Entity 
public class Person { 
    public long personId; 
    private String name; 
    public Heart heart; 
    public Liver liver; 
    // other fields 

    @Id 
    @GeneratedValue 
    public long getPersonId() {return personId;} 

    @OneToOne(cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    public Heart getHeart() {return heart;} 

    public void setHeart(Heart heart){ 
     this.heart = heart; 
     this.heart.setPerson(this); 
    } 

    @OneToOne(cascade = CascadeType.ALL) 
    @PrimaryKeyJoinColumn 
    public Liver getLiver() {return liver;} 

    public void setLiver(Liver liver){ 
     this.liver = liver; 
     this.liver.setPerson(this); 
    } 
    // other getters and setters and constructors 
} 
+0

Я пробовал пример из документации, но я не понимаю, как это работает: нет ничего, чтобы согласовать идентификаторы между тремя таблицами. Единственная причина, по которой у меня есть поле человека в классах «Сердце» и «Печень», - для иностранного @GenericGenerator, так что все объекты Heart and Liver будут иметь тот же идентификатор, что и соответствующий объект Person. ПРИМЕЧАНИЕ. Я получаю ту же ошибку, что и в вопросе, если я удалю @OneToOne и @PrimaryKeyJoinColumn из getPerson() в классах Сердце и Печень. – jackocnr

1

Я не пробовал, но я бы сказал, что ....

Разница между обеими сторонами заключается в том, что Person класс не имеет mappedBy в своем картографии.

Таким образом, для каждого индивидуального пользователя Person имеет ссылочное значение, которое считается Hibernate официальным. Напротив, на других объектах, mappedBy указывает на Hibernate, чтобы не использовать значение, но перейдите к этому объекту и рассмотрите отображаемое свойство на этом объекте.


Чтобы проверить, если я прав, вы можете установить только те значения, которые не имеют mappedBy и сохранить Person объект (потому что это тот, который имеет каскады), и посмотреть, если результат является правильным .. ;-)

+0

Я могу просто создать новый объект Person, установить его имя и спасти его без каких-либо ошибок. Но если я создаю новый объект Heart, установите его поле bpm и сохраните его, я снова получу это IdentifierGenerationException. Это то, что вы имеете в виду? Вы знаете обходное решение? – jackocnr

Смежные вопросы