web-dev-qa-db-fra.com

JPA Hibernate One-to-One relation

J'ai une relation un à un, mais hibernatetool se plaint lors de la génération du schéma. Voici un exemple qui montre le problème:

@Entity
public class Person {
    @Id
    public int id;

    @OneToOne
    public OtherInfo otherInfo;

    rest of attributes ...
}

La personne a une relation individuelle avec OtherInfo:

@Entity
public class OtherInfo {
    @Id
    @OneToOne(mappedBy="otherInfo")
    public Person person;

    rest of attributes ...
}

La personne possède le côté OtherInfo. OtherInfo est le côté possédé, donc personne utilise mappedBy pour spécifier le nom d'attribut "otherInfo" dans Person.

J'obtiens l'erreur suivante lorsque j'utilise hibernatetool pour générer le schéma de base de données:

org.hibernate.MappingException: Could not determine type for: Person, at table: OtherInfo, for columns: [org.hibernate.mapping.Column(person)]
        at org.hibernate.mapping.SimpleValue.getType(SimpleValue.Java:292)
        at org.hibernate.mapping.SimpleValue.createIdentifierGenerator(SimpleValue.Java:175)
        at org.hibernate.cfg.Configuration.iterateGenerators(Configuration.Java:743)
        at org.hibernate.cfg.Configuration.generateDropSchemaScript(Configuration.Java:854)
        at org.hibernate.tool.hbm2ddl.SchemaExport.<init>(SchemaExport.Java:128)
        ...

Une idée pourquoi? Suis-je en train de faire quelque chose de mal ou est-ce un bug Hibernate?

62
Steve Kuo

JPA n'autorise pas l'annotation @ Id sur un mappage OneToOne ou ManyToOne. Ce que vous essayez de faire est une association d'entité un-à-un avec une clé primaire partagée . Le cas le plus simple est un à un unidirectionnel avec une clé partagée:

@Entity
public class Person {
    @Id
    private int id;

    @OneToOne
    @PrimaryKeyJoinColumn
    private OtherInfo otherInfo;

    rest of attributes ...
}

Le principal problème avec cela est que JPA ne prend pas en charge la génération de clé primaire partagée dans l'entité OtherInfo. Le livre classique Java Persistence with Hibernate by Bauer and King donne la solution suivante au problème d'utilisation de l'extension Hibernate:

@Entity
public class OtherInfo {
    @Id @GeneratedValue(generator = "customForeignGenerator")
    @org.hibernate.annotations.GenericGenerator(
        name = "customForeignGenerator",
        strategy = "foreign",
        parameters = @Parameter(name = "property", value = "person")
    )
    private Long id;

    @OneToOne(mappedBy="otherInfo")
    @PrimaryKeyJoinColumn
    public Person person;

    rest of attributes ...
}

Voir aussi ici .

85
topchef

Cela devrait également fonctionner en utilisant l'annotation JPA 2.0 @MapsId au lieu du GenericGenerator d'Hibernate:

@Entity
public class Person {

    @Id
    @GeneratedValue
    public int id;

    @OneToOne
    @PrimaryKeyJoinColumn
    public OtherInfo otherInfo;

    rest of attributes ...
}

@Entity
public class OtherInfo {

    @Id
    public int id;

    @MapsId
    @OneToOne
    @JoinColumn(name="id")
    public Person person;

    rest of attributes ...
}

Plus de détails à ce sujet dans la documentation Hibernate 4.1 sous la section 5.1.2.2.7.

23
Mariusz

Il vous suffit d'ajouter @JoinColumn(name="column_name") à la relation Entité hôte. nom_colonne est le nom de la colonne de base de données dans la table personne.

@Entity
public class Person {
    @Id
    public int id;

    @OneToOne
    @JoinColumn(name="other_info")
    public OtherInfo otherInfo;

    rest of attributes ...
}

Personne a une relation un à un avec OtherInfo: mappedBy = "nom_vari" nom_vari est le nom de variable pour otherInfo dans la classe Personne.

@Entity
public class OtherInfo {
    @Id
    @OneToOne(mappedBy="otherInfo")
    public Person person;

    rest of attributes ...
}
10
Igor Sadovnikov

Je pense que vous avez toujours besoin de la propriété de clé primaire dans la classe OtherInfo.

@Entity
public class OtherInfo {
    @Id
    public int id;

    @OneToOne(mappedBy="otherInfo")
    public Person person;

    rest of attributes ...
}

En outre, vous devrez peut-être ajouter l'annotation @PrimaryKeyJoinColumn de l'autre côté du mappage. Je sais qu'Hibernate l'utilise par défaut. Mais je n'ai pas utilisé d'annotations JPA, ce qui semble vous obliger à spécifier comment fonctionne l'association.

4
waxwing

J'ai une meilleure façon de procéder:

@Entity
public class Person {

    @OneToOne(cascade={javax.persistence.CascadeType.ALL})
    @JoinColumn(name = "`Id_OtherInfo`")
    public OtherInfo getOtherInfo() {
      return otherInfo;
    }

}

C'est tout

2
Vodo-Siosk Baas

Je ne suis pas sûr que vous puissiez utiliser une relation comme identifiant/clé primaire dans Hibernate.

1
razenha

Essaye ça

@Entity

@Table(name="tblperson")

public class Person {

public int id;

public OtherInfo otherInfo;
@Id //Here Id is autogenerated
@Column(name="id")
@GeneratedValue(strategy=GenerationType.AUTO)
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}

@OneToOne(cascade = CascadeType.ALL,targetEntity=OtherInfo.class)
@JoinColumn(name="otherInfo_id") //there should be a column otherInfo_id in Person
public OtherInfo getOtherInfo() {
    return otherInfo;
}
public void setOtherInfo(OtherInfo otherInfo) {
    this.otherInfo= otherInfo;
}
rest of attributes ...
}


@Entity

@Table(name="tblotherInfo")

public class OtherInfo {

private int id;

private Person person;

@Id

@Column(name="id")
@GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
    return id;
}
public void setId(Long id) {
    this.id = id;
}

  @OneToOne(mappedBy="OtherInfo",targetEntity=Person.class)   
public College getPerson() {
    return person;
}
public void setPerson(Person person) {
    this.person = person;
}    
 rest of attributes ...
}
1
Jugal