inheritance - joined - jpa mapeo
Herencia JPA exige ID en subclase (7)
Tengo un problema con mi modelo de dominio jpa. Solo estoy tratando de jugar con la herencia simple para la que uso una clase base simple de persona y una subclase de cliente. De acuerdo con la documentación oficial (tanto, JPA como EclipseLink) solo necesito el atributo / columna ID en la clase base. Pero cuando ejecuto mis pruebas, siempre recibo un error que me dice que el cliente no tiene @Id?
Primero pensé que el problema radica en la visibilidad del atributo-id, porque primero era privado. Pero incluso después de cambiarlo a protegido (para que la subclase tenga acceso directo) no funciona.
Persona:
@Entity @Table(name="Persons")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "TYPE")
public class Person {
@Id
@GeneratedValue
protected int id;
@Column(nullable = false)
protected String firstName;
@Column(nullable = false)
protected String lastName;
Cliente:
@Entity @Table(name = "Customers")
@DiscriminatorValue("C")
public class Customer extends Person {
//no id needed here
Me estoy quedando sin ideas y recursos para mirar. Debería ser un problema bastante simple, pero simplemente no lo veo.
Como he visto algunas respuestas que pueden ayudar, pero no una respuesta completa, intentaré proporcionar una.
Como indica la respuesta aceptada, debe declarar la herencia en la clase base. Hay 4 formas diferentes de hacerlo:
- @MappedSuperclass
Mapeará cada clase concreta a la mesa
- @ Herencia (estrategia = HerenciaTipo.TABLE_PER_CLASS)
Similar a @MappedSuperclass pero la superclase es también una entidad
- @ Herencia (estrategia = Tipo de herencia.SINGLE_TABLE)
Todas las clases concretas serán mapeadas por la misma tabla.
- @ Herencia (estrategia = HerenciaTipo.JUINADO)
Cada clase tiene su propia mesa. Los campos unidos serán asignados por la tabla para la superclase abstracta.
Puedes leer más sobre estrategias de herencia JPA aquí:
https://www.thoughts-on-java.org/complete-guide-inheritance-strategies-jpa-hibernate/
Si la estructura de clases se divide en diferentes proyectos, es posible que tenga que declarar la superclase en su persistence.xml, como tk.luczak declaró en su respuesta
JPA conoce dos formas diferentes de aplicar la herencia:
- Herencia de tablas unidas
- Herencia de tabla única
Con la herencia de una sola tabla, necesitará una columna discriminadora para distinguir entre las filas de la tabla.
Con la herencia de tablas unidas, cada clase obtiene su propia tabla, por lo que no se necesita una columna discriminadora.
Creo que tu problema es que has mezclado los dos conceptos. Entonces, o bien:
- defina las columnas discriminadoras y use `InheritanceType.SINGLE_TABLE` y no use` @ Table` en las subclases
- o use `InheritanceType.JOINED` pero no especifique la columna y los valores del discriminador.
Lo resolví yo mismo creando una MappedSuperclass
@MappedSuperclass
public abstract class EntityBase{
@Id
@GeneratedValue
private int id;
...setter/getter
}
Todas las entidades están heredando de esta clase. Todavía me pregunto por qué los tutoriales no mencionan esto, pero tal vez mejore con las implementaciones de JPA 2.
Podría obtener este tipo de error cuando no esté generando el esquema de base de datos basado en sus entidades. Si ese es el caso:
1º - Tu superclase siempre debe tener un @Id
2do: su subclase debe tener alguna columna que identifique la clase extendida (super clase @Id)
Tercero: la solución más sencilla para el caso presentado anteriormente sería agregar una identificación de columna a la tabla de subclases, con la restricción de clave externa correspondiente.
¡Espero que esto ayude a alguien! ¡Pulgares hacia arriba!
Puede haber otra razón para este error cuando se usa Glassfish / EclipseLink: EclipseLink <2.6.0 tiene un error desagradable que hace que se ignoren las clases con expresiones lambda. Esto puede llevar a errores confusos, como el que se menciona aquí, u otros errores similares (por ejemplo, EclipseLink puede decirle que una clase con una anotación @Entity no es una entidad).
Glassfish 4.1 incluye EclipseLink 2.5.x, por lo que este error (y muchos otros) lo picará si usa Glassfish. Estaba usando esta versión en lugar de 4.1.1 debido a otro error que hacía imposible utilizar la validación en los servicios web REST. Manténgase lo más alejado posible de Glassfish si desea mantener su cordura.
Sé que esto es viejo pero no obstante válido. Tuve el mismo problema. Sin embargo, @MappedSuperClass no es lo mismo que una tabla de herencia única. MappedSuperClass creará tablas separadas para cada una de las subclases (según entiendo)
No estoy seguro exactamente por qué, pero cuando solo tengo una clase heredada no tuve problemas. Sin embargo, una vez que agregué el segundo y el tercero, recibí el mismo error. Cuando especifiqué la anotación @Id en la tabla secundaria, comenzó a funcionar nuevamente.
Mi diseño era simple, información de contacto para Compañías, Agentes y Clientes.
Tabla principal:
...
@Entity
@Inheritance(strategy= InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="USER_TYPE", length=10, discriminatorType= DiscriminatorType.STRING)
@Table(name="CONTACTS")
public abstract class AbstractContact implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
@Column (length=10, nullable=false)
protected String mapType;
@Column (length=120, nullable=false)
protected String mapValue;
...
Contactos del agente
@Entity
@DiscriminatorValue("Agent")
public class AgentContact extends AbstractContact implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="USER_ID")
protected Agents agent;
}
Contacto de la empresa:
@Entity
@DiscriminatorValue("Company")
public class CompanyContact extends AbstractContact implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="USER_ID")
protected Companies company;
}
Contactos del cliente:
@Entity
@DiscriminatorValue("Client")
public class ClientContact extends AbstractContact implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
//Client table not built yet so... no mapping
}
La tabla de clientes aún no se ha creado, por lo que no hay información de asignación, pero se entiende el punto.
Quería compartir la descripción de MySQL, ¡pero el Símbolo del sistema de Windows no vale para cortar / copiar / pegar! En esencia, su: ID (int pri) USER_TYPE (VARCHAR (10)) USER_ID (INT) MAPTYPE (VARCHAR (10)) MAPVALUE (VARCHAR (120))
Todavía tengo que configurar todas las pruebas, pero hasta ahora se ve bien (me temo que si espero hasta después de hacer todas las pruebas, me olvidaré de publicar esto)
Tuve exactamente el mismo problema. Para la subclase estaba obteniendo:
Entity class [...] has no primary key specified. It should define either an @Id, @EmbeddedId or an @IdClass.
En mi caso, resultó que olvidé agregar mi clase raíz en persistence.xml
.
Asegúrese de tener tanto persona como cliente definidos en:
<persistence>
<persistence-unit>
...
<class>package.Person</class>
<class>package.Customer</class>
...
</persistence-unit>
</persistence>