2009-04-24 13 views
59

Tengo una relación uno a uno, pero hibernatetool se queja cuando genera el esquema. He aquí un ejemplo que muestra el problema:Relación JPA Hibernate uno a uno

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

    @OneToOne 
    public OtherInfo otherInfo; 

    rest of attributes ... 
} 

persona tiene una relación uno-a-uno con OtherInfo:

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

    rest of attributes ... 
} 

persona es propietaria lado de OtherInfo. OtherInfo es el lado de propiedad así que la persona usa mappedBy para especificar el nombre de atributo "otherInfo" en Person.

me sale el siguiente error al utilizar hibernatetool para generar el esquema de base de datos:

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) 
     ... 

Cualquier idea de por qué? ¿Estoy haciendo algo mal o es un error de Hibernate?

Respuesta

85

APP no permite la anotación @Id en un OneToOne o ManyToOne mapeo. Lo que está intentando hacer es una asociación de entidad uno a uno con clave primaria compartida. El caso más simple es unidireccional uno-a-uno con clave compartida:

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

    @OneToOne 
    @PrimaryKeyJoinColumn 
    private OtherInfo otherInfo; 

    rest of attributes ... 
} 

El principal problema con esto es que la APP no ofrece soporte para la generación de la clave principal compartida en OtherInfo entidad. El libro clásico Java Persistence with Hibernate by Bauer and King da la siguiente solución al problema mediante la extensión de hibernación:

@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 ... 
} 

Además, vea here.

+3

Gran respuesta, sólo quería añadir que es posible que tenga que añadir la siguiente anotación así en su clase de la persona (que tenía que hacer las cosas funcionan correctamente): '@Cascade ({CascadeType.ALL, CascadeType. DELETE_ORPHAN}) ' –

+0

Gracias, me ayudó en mi problema .. ¿Sabes de todos modos usar solo anotaciones JPA y evitar la hibernación? – Elton

+0

@Elton - si hay una manera en la que debe estar en JPA 2.0 - No lo analicé. – topchef

1

No estoy seguro de que pueda usar una relación como Id/PrimaryKey en Hibernate.

1

probar este

@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 ... 
} 
4

creo que aún necesita la propiedad clave primaria en la clase OtherInfo.

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

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

    rest of attributes ... 
} 

Además, es posible que tenga que añadir la anotación @PrimaryKeyJoinColumn al otro lado de la asignación. Sé que Hibernate usa esto por defecto. Pero luego no he usado las anotaciones JPA, que parecen requerir que especifiques cómo funciona la asociación.

2

tengo una mejor forma de hacer esto:

@Entity 
public class Person { 

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

} 

Eso es todo

+0

También el lado de propiedad, es decir, el lado que tiene la clave foránea debe implementar serializable (con hiberate 4/jpa 2) –

22

Esto debería estar trabajando demasiado usando JPA 2.0 @MapsId anotación en lugar de GenericGenerator de 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 ... 
} 

Más detalles sobre esto en la documentación de Hibernate 4.1 en la sección 5.1.2.2.7.

+1

[Enlace para el perezoso] (https://docs.jboss.org/hibernate/orm/4.1/manual/es-ES/html_single/# d5e2666). Elegí usar la anotación Id en la clase OneToOne misma (OtherInfo en su ejemplo), pero eso solo funciona en un escenario padre-hijo. ¡Gracias por la respuesta! – Joe

+2

¿Por qué especificó '@ JoinColumn' en' OtherInfo' en lugar de usar '@ PrimaryKeyJoinColumn'? –

10

Solo tiene que agregar @JoinColumn(name="column_name") a la relación Entidad de host. column_name es el nombre de la columna de la base de datos en la tabla de personas.

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

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

    rest of attributes ... 
} 

persona tiene una relación uno-a-uno con OtherInfo: mappedBy = var_name "var_name" es nombre de variable para otherInfo en la clase de persona.

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

    rest of attributes ... 
} 
Cuestiones relacionadas