mvc localcontainerentitymanagerfactorybean example entitymanagerfactory data java hibernate spring orm jpa

java - localcontainerentitymanagerfactorybean - Omitir GeneratedValue en Hibernate(fusionar datos no en db?)



spring jpa configuration (7)

Mi problema es el mismo que se describe en [1] o [2] . Necesito configurar manualmente un valor autogenerado por defecto ( ¿por qué? Importar datos antiguos ). Como se describe en [1] usando la entity = em.merge(entity) de Hibernate entity = em.merge(entity) hará el truco.

Desafortunadamente para mí no es así. No recibo un error ni ninguna otra advertencia. La entidad simplemente no va a aparecer en la base de datos . Estoy usando Spring and Hibernate EntityManager 3.5.3-Final.

¿Algunas ideas?


Actualizando la respuesta de Laurent Grégoire para hibernate 5.2 porque parece haber cambiado un poco.

public class UseExistingIdOtherwiseGenerateUsingIdentity extends IdentityGenerator { @Override public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException { Serializable id = session.getEntityPersister(null, object).getClassMetadata().getIdentifier(object, session); return id != null ? id : super.generate(session, object); } }

y utilícelo así: (reemplace el nombre del paquete)

@Id @GenericGenerator(name = "UseExistingIdOtherwiseGenerateUsingIdentity", strategy = "{package}.UseExistingIdOtherwiseGenerateUsingIdentity") @GeneratedValue(generator = "UseExistingIdOtherwiseGenerateUsingIdentity") @Column(unique = true, nullable = false) protected Integer id;



Estoy dando una solución aquí que funcionó para mí:
crea tu propio generador de identificador / generador de secuencia

public class FilterIdentifierGenerator extends IdentityGenerator implements IdentifierGenerator{ @Override public Serializable generate(SessionImplementor session, Object object) throws HibernateException { // TODO Auto-generated method stub Serializable id = session.getEntityPersister(null, object) .getClassMetadata().getIdentifier(object, session); return id != null ? id : super.generate(session, object); } }

modifique su entidad como:

@Id @GeneratedValue(generator="myGenerator") @GenericGenerator(name="myGenerator", strategy="package.FilterIdentifierGenerator") @Column(unique=true, nullable=false) private int id; ...

y al guardar en lugar de usar persist() use merge() o update()


Necesitas una transacción en ejecución.

En caso de que su transacción se administre manualmente:

entityManager.getTransaction().begin();

(por supuesto no te olvides de cometer)

Si está utilizando transacciones declarativas, use la declaración apropiada (a través de anotaciones, lo más probable)

Además, establezca el nivel de registro de hibernación para debug ( log4j.logger.org.hibernate=debug ) en su log4j.properties para rastrear lo que está sucediendo en más detalles.


Otra implementación, mucho más simple.

Éste funciona con configuración basada en anotaciones o basada en xml: se basa en los metadatos de hibernación para obtener el valor de identificación para el objeto. Reemplace SequenceGenerator por IdentityGenerator (o cualquier otro generador) dependiendo de su configuración. (La creación de un decorador en lugar de subclases, pasando el generador de ID decorado como un parámetro para este generador, se deja como un ejercicio para el lector).

public class UseExistingOrGenerateIdGenerator extends SequenceGenerator { @Override public Serializable generate(SessionImplementor session, Object object) throws HibernateException { Serializable id = session.getEntityPersister(null, object) .getClassMetadata().getIdentifier(object, session); return id != null ? id : super.generate(session, object); } }

Responda al ejercicio (usando un patrón de decorador, como se solicita), no realmente probado:

public class UseExistingOrGenerateIdGenerator implements IdentifierGenerator, Configurable { private IdentifierGenerator defaultGenerator; @Override public void configure(Type type, Properties params, Dialect d) throws MappingException; // For example: take a class name and create an instance this.defaultGenerator = buildGeneratorFromParams( params.getProperty("default")); } @Override public Serializable generate(SessionImplementor session, Object object) throws HibernateException { Serializable id = session.getEntityPersister(null, object) .getClassMetadata().getIdentifier(object, session); return id != null ? id : defaultGenerator.generate(session, object); } }


Para cualquier otra persona que busque hacer esto, arriba funciona bien. Solo una recomendación para obtener el identificador del objeto en lugar de tener herencia para cada clase de Entidad (Solo para el ID), podría hacer algo como:

import org.hibernate.id.IdentityGenerator; public class UseIdOrGenerate extends IdentityGenerator { private static final Logger log = Logger.getLogger(UseIdOrGenerate.class .getName()); @Override public Serializable generate(SessionImplementor session, Object object) throws HibernateException { if (object == null) throw new HibernateException(new NullPointerException()); for (Field field : object.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(Id.class) && field.isAnnotationPresent(GeneratedValue.class)) { boolean isAccessible = field.isAccessible(); try { field.setAccessible(true); Object obj = field.get(object); field.setAccessible(isAccessible); if (obj != null) { if (Integer.class.isAssignableFrom(obj.getClass())) { if (((Integer) obj) > 0) { return (Serializable) obj; } } } } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } return super.generate(session, object); } }


funciona en mi proyecto con el siguiente código:

@XmlAttribute @Id @Basic(optional = false) @GeneratedValue(strategy=GenerationType.IDENTITY, generator="IdOrGenerated") @GenericGenerator(name="IdOrGenerated", strategy="....UseIdOrGenerate" ) @Column(name = "ID", nullable = false) private Integer id;

y

import org.hibernate.id.IdentityGenerator; ... public class UseIdOrGenerate extends IdentityGenerator { private static final Logger log = Logger.getLogger(UseIdOrGenerate.class.getName()); @Override public Serializable generate(SessionImplementor session, Object obj) throws HibernateException { if (obj == null) throw new HibernateException(new NullPointerException()) ; if ((((EntityWithId) obj).getId()) == null) { Serializable id = super.generate(session, obj) ; return id; } else { return ((EntityWithId) obj).getId(); } }

donde básicamente defines tu propio generador de ID (basado en la estrategia de Identidad), y si el ID no está establecido, delegas la generación al generador predeterminado.

El principal inconveniente es que lo conecta con Hibernate como proveedor de JPA ... pero funciona perfectamente con mi proyecto MySQL