My problem is the same as described in [1] or [2]. I need to manually set a by default auto-generated value (why? importing old data). As described in [1] using Hibernate's entity = em.merge(entity)
will do the trick.
Unfortunately for me it does not. I neither get an error nor any other warning. The entity is just not going to appear in the database. I'm using Spring and Hibernate EntityManager 3.5.3-Final.
Any ideas?
So the merge method does exactly that: finds an entity instance by id taken from the passed object (either an existing entity instance from the persistence context is retrieved, or a new instance loaded from the database) copies fields from the passed object to this instance. returns a newly updated instance.
SEQUENCE is the generation type recommended by the Hibernate documentation. The generated values are unique per sequence. If we don't specify a sequence name, Hibernate will reuse the same hibernate_sequence for different types.
persistence. GeneratedValueJPA annotationProvides for the specification of generation strategies for the values of primary keys. See JavaDoc Reference Page... annotation specifies that a value will be automatically generated for that field.
If you want to use a custom generator, you need to define the generator in a @GenericGenerator annotation and provide the fully-qualified classname as the strategy. You can also configure a set of parameters that will be provided to the configure method when Hibernate instantiates the generator.
Another implementation, way simpler.
This one works with both annotation-based or xml-based configuration: it rely on hibernate meta-data to get the id value for the object. Replace SequenceGenerator
by IdentityGenerator
(or any other generator) depending on your configuration. (The creation of a decorator instead of subclassing, passing the decorated ID generator as a parameter to this generator, is left as an exercise to the reader).
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); } }
Answer to the exercise (using a decorator pattern, as requested), not really tested:
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); } }
it works on my project with the following code:
@XmlAttribute @Id @Basic(optional = false) @GeneratedValue(strategy=GenerationType.IDENTITY, generator="IdOrGenerated") @GenericGenerator(name="IdOrGenerated", strategy="....UseIdOrGenerate" ) @Column(name = "ID", nullable = false) private Integer id;
and
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(); } }
where you basically define your own ID generator (based on the Identity strategy), and if the ID is not set, you delegate the generation to the default generator.
The main drawback is that it bounds you to Hibernate as JPA provider ... but it works perfectly with my MySQL project
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With