java - example - Hibernate y sin PK
java jpa example (9)
Añadiendo al comentario de Awied. Si luego quieres buscar una barra, utiliza el siguiente HQL.
Query fooQuery = getSession().createQuery("from Foo.id.bar = ''<barName>''");
¿Es posible crear una tabla (desde un hibernate @Entity
anotación JPA) que no contenga una clave / identificación principal?
Sé que esta no es una buena idea; una tabla debe tener una clave principal.
Cuando se trata de vistas en lugar de buscar soluciones en Hibernate, puede ser más fácil agregar una identificación ficticia en la vista de la base de datos. Escribí al respecto en otra pregunta: https://.com/a/44050230/1673775
Descubrí que este truco funciona:
<id column="ROWID" type="string" />
Descubrí que no es posible hacerlo. Tan mala suerte para aquellos que trabajan con sistemas heredados.
Si realiza ingeniería inversa (cree entidades anotadas por JPA a partir de una conexión JDBC existente), la tabla creará dos clases Java, una entidad y un campo; id, y una identificación incrustable que contiene todas las columnas de su relación.
Encontré solución para tablas sin clave primaria y nula como valores. Funcionará en Oracle DB. Tal vez algo similar existe para otras DB.
Debería crear una nueva clave primaria en la clase POJO:
@Id @Column (name = "id") private Integer id;
y usa createNativeQuery como este
getEntityManager().createNativeQuery("select rownum as id, .....
La consulta nativa generará la clave principal y obtendrá resultados únicos.
La auto-respuesta de Roger es correcta. Para elaborar un poco sobre lo que significa (al principio no estaba claro y pensé que esto ayudaría):
Digamos que tiene una mesa Foo como tal:
TABLE Foo (
bar varchar(20),
bat varchar(20)
)
Normalmente, puede escribir una clase con anotaciones para trabajar con esta tabla:
// Technically, for this example, the @Table and @Column annotations
// are not needed, but don''t hurt. Use them if your column names
// are different than the variable names.
@Entity
@Table(name = "FOO")
class Foo {
private String bar;
private String bat;
@Column(name = "bar")
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
@Column(name = "bat")
public String getBat() {
return bat;
}
public void setBat(String bat) {
this.bat = bat;
}
}
.. Pero, maldición. Esta tabla no tiene nada que podamos usar como identificación, y es una base de datos heredada que usamos para [inserte la función comercial vital]. No creo que me dejen modificar las tablas para que pueda usar hibernate.
En cambio, puede dividir el objeto en una estructura viable de hibernación que permita utilizar toda la fila como clave. (Naturalmente, esto supone que la fila es única).
Dividir el objeto Foo en dos así:
@Entity
@Table(name = "FOO")
class Foo {
@Id
private FooKey id;
public void setId(FooKey id) {
this.id = id;
}
public void getId() {
return id;
}
}
y
@Embeddable
class FooKey implements Serializable {
private String bar;
private String bat;
@Column(name = "bar")
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
@Column(name = "bat")
public String getBat() {
return bat;
}
public void setBat(String bat) {
this.bat = bat;
}
}
.. Y eso debería ser. Hibernate usará la tecla Incrustar para su identidad requerida y puede hacer una llamada de la forma habitual:
Query fooQuery = getSession().createQuery("from Foo");
Espero que esto ayude a los principiantes a hacer que esto funcione.
No necesita crear una clase separada para ser su @Id o clave principal. Solo usa un Entero (o lo que sea). Además, no publique la clave falsa ya que los desarrolladores que la usan pueden pensar que es real y, de lo contrario, intentar usarla. Por último, esto se utiliza mejor en una VISTA. Estoy de acuerdo con las publicaciones anteriores que en la mayoría, si no en todos los casos, las tablas deben tener una clave principal. Por ejemplo:
@Entity
@Table(name = "FOO")
class Foo {
@SuppressWarnings("unused")
@Id
private Integer id;
@Column(name = "REAL_COLUMN")
private String realColumn;
public String getRealColumn() {
return realColumn;
}
public void setRealColumn(String realColumn) {
this.realColumn= realColumn;
}
}
Para crear el Pojo de la tabla, use el método de ingeniería inverso existente en eclipse. Para la tabla de clave no primaria, eclipse generará las dos clases de Pojo.
eclipse generated class and hbm.xml -
---
Foo.java
//
public class Foo implements java.io.Serializable {
private FooId id;
public Foo() {
}
public Foo(FooId id) {
this.id = id;
}
public FooId getId() {
return this.id;
}
public void setId(FooId id) {
this.id = id;
}
}
---
FooId.java
//
public class FooId implements java.io.Serializable {
private String bar;
private String bat;
public FooId() {
}
public FooId(String bar, String bat) {
this.bar = bar;
this.bat = bat;
}
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
public String getBat() {
return this.bat;
}
public void setBat(String bat) {
this.bat = bat;
}
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof FooId))
return false;
FooId castOther = (FooId) other;
return ((this.getBar() == castOther.getBar()) || (this.getBar() != null
&& castOther.getBar() != null && this.getBar().equals(
castOther.getBar())))
&& ((this.getBat() == castOther.getBat()) || (this.getBat() != null
&& castOther.getBat() != null && this.getBat().equals(
castOther.getBat())));
}
public int hashCode() {
int result = 17;
result = 37 * result
+ (getBar() == null ? 0 : this.getBar().hashCode());
result = 37 * result
+ (getBat() == null ? 0 : this.getBat().hashCode());
return result;
}
}
---
Foo.hbm.xml
<hibernate-mapping>
<class name="com.Foo" table="foo" schema="public" catalog="hibernate_poc">
<composite-id name="id" class="com.FooId">
<key-property name="bar" type="string">
<column name="bar" length="20" />
</key-property>
<key-property name="bat" type="string">
<column name="bat" length="20" />
</key-property>
</composite-id>
</class>
</hibernate-mapping>
---
entry in the Hibernate.cfg.xml -
<mapping class="com.poc.Foo" resource="Foo.hbm.xml"/>
---
Fetch the Data from table -
FooDataFetch.java
//
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class FooDataFetch {
private static Session session = null;
public static void main(String[] args) {
try{
Configuration cfg = new Configuration();
cfg.configure("/hibernate.cfg.xml");
SessionFactory sf = cfg.buildSessionFactory();
session = sf.openSession();
session.beginTransaction();
queryPerson(session);
session.close();
}catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
ex.printStackTrace();
throw new ExceptionInInitializerError(ex);
}
}
private static void queryPerson(Session session) {
Query query = session.createQuery("from Foo");
List <Foo>list = query.list();
java.util.Iterator<Foo> iter = list.iterator();
while (iter.hasNext()) {
Foo foo = iter.next();
System.out.println("Foo Details: /"" + foo.getId().getBar() +"/", " + foo.getId().getBat());
}
}
}
Use el siguiente código; Hibernate no tiene su propia lógica para distinguir registros duplicados
Avíseme si hay algún problema con este enfoque
@Entity @IdClass(Foo.class)
class Foo implements Serializable {
@Id private String bar;
@Id private String bat;
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
public String getBat() {
return bat;
}
public void setBat(String bat) {
this.bat = bat;
}
}