How override getter of id column in jpa configuration [duplicate] - java

This question already has answers here:
Hibernate : How override an attribute from mapped super class
(2 answers)
Closed 5 years ago.
I have a problem for #Id in JPA that is described as follow?
There is a generic class as follow?
#MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
private static final long serialVersionUID = 4295229462159851306L;
private T id;
public T getId() {
return id;
}
public void setId(T id) {
this.id = id;
}
}
There is another class that extends from it as follow?
#Entity
#Table(name = "DOC_CHANGE_CODE" )
public class ChangeCode extends BaseEntity<Long> {
#Id
#GeneratedValue(generator = "sequence_db", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "sequence_db", sequenceName = "SEQ_DOC_CHANGE_CODE", allocationSize = 1)
public Long getId () {
return super.getId();
}
}
Because any sub class has its own sequence, I must specific any subclass #Id, because of that I override the its getter and put some annotations in top of that. Unfortunately it does not work correctly.
How do I fix problem and get my goal?

Try this:
#Entity
#Table(name = "DOC_CHANGE_CODE" )
#SequenceGenerator(name = "sequence_db", sequenceName = "SEQ_DOC_CHANGE_CODE", allocationSize = 1)
#AttributeOverride(name = "id", column = #Column(name = "ID"))
public class ChangeCode extends BaseEntity<Long> {
#Override
#Id
#GeneratedValue(generator = "sequence_db", strategy = GenerationType.SEQUENCE)
public Long getId() {
return id;
}
}

It's not possible to override the #Id from a base class.
The only way to do it is to provide your own custom IentifierGenerator and provide a different logic based on the subclass (e.g. using a sequence name based on the subclass name).
That's why adding the #Id attribute in the #MappedSuperclass only makes sense for the assigned generator or for IDENTITY.

Related

How to have different annotations applied to an entity property?

I have an abstract base entity class with an id property.
I would like to have specific annotations applied to this property if the current database is H2:
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = id_generator")
#Column(name = "id")
private Long id;
And some other specific anotations applied to this property if the current database is MySQL:
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name = "native", strategy = "native")
#Column(name = "id")
private Long id;
The base class:
#MappedSuperclass
public abstract class AbstractEntity {
All entity classes extend the base class like:
#Entity
#Table(name = "user_account")
#SequenceGenerator(name = "id_generator", sequenceName = "sq_id_user")
public class User extends AbstractEntity {
Maybe I could leverage some conditional custom annotations ?
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Conditional(DbH2Condition.class)
public #interface DbH2 {
}
public class DbH2Condition implements Condition {
private static final String DB = "h2";
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("db") == null
|| context.getEnvironment().getProperty("db").equals(DB);
}
}
you can add annotations using external byte code manipulation framework, such as JavaAssist, during compile time. But it means that you need to know in compile time of course, which database you will use.

Hibernate object ID

I'm trying to use objects as #Id but Hibernate doesn't seem to convert the object to the corresponding primitive type stated using an AttributeConverter.
#Entity
#Table(name = "ris_exam")
public class Exam {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long examId;
}
public class ExamId {
private Long id;
public ExamId(final Long id) {
super();
this.id = id;
}
public Long getId() {
return this.id;
}
}
#Converter(autoApply = true)
public class ExamIdCodeAttributeConverter implements AttributeConverter<ExamId, Long> {
#Override
public Long convertToDatabaseColumn(ExamId arg0) {
return arg0.getId();
}
#Override
public ExamId convertToEntityAttribute(Long arg0) {
return new ExamId(arg0);
}
}
Hibernate does this query when creating the table
create table ris_exam (id varbinary(255) identity not null, ...)
If you want to play around with wrapping of the basic column then you must take into consideration that most likely you will not be able to use the #GeneratedValue annotation on your id (the same goes for using the #EmbeddedId which is more suitable than the converter in my opinion anyway).
If you need to anyway then in my opinion you could try the #IdClass feature but remember that the ExamId class would only be used while specifiying the queries / retrieving specific entity:
#Entity
#Table(name = "ris_exam")
#IdClass(ExamId.class)
public class Exam {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long examId;
}
in DAO:
ExamId id = new ExamId(1L);
session.get(Exam.class, id);
when retrieved, the entities would contain plain long types.
Just an option for you to consider..

Hibernate subclass id generation in table per subclass

When im using table-per-subclass strategy my base (parent class) contains compound primary.
#Column(nullable = false)
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XXX")
#SequenceGenerator(name = "XXX", sequenceName = "XXX", allocationSize = 1)
private Long systemId;
#Id
#Column(nullable = false)
private Long version;
So, all entities that extend this (as i got it) inherit ids and its annotated properties.
The problem, is that when i create a new Parent entity, the primary is being created from sequence, thats ok. But when i create subclass instance it increments my parent id i dont need (creates a new primary from seq.), `coz i use table-per-subclass and primaries gottta be the same.
Question: how to supress id generation in Subclasses?
#Entity
#PrimaryKeyJoinColumns(
{
#PrimaryKeyJoinColumn(name = "systemId"),
#PrimaryKeyJoinColumn(name = "version")
}
)
public class SUb extends Parent {
public SUb (Parent t) {
super(t);
}
public SUb () {
}
...
... no ids...
When the Subclass is created it will issue two inserts:
one in the base class
one in the sub class
The subclass doesn't inherit the #Ids, but instead it uses the:
systemId
version
as FK to the associated columns of the Base table.
So while the base class has a primary key composed of those two columns:
a sequence generated systemId
a manually assigned version
The subclass should have:
a sequnceId column with a FK to the base sequnceId column
a version column with a FK to the base version column
So the sequence shouldn't be called twice while inserting a sub class entity.
Can you confirm that the database tables are following this design?
I couldn't manage to reproduce your problem. Can you be more specific on what is your join strategy? Is it InheritanceType.TABLE_PER_CLASS or InheritanceType.JOINED? Nonetheless I managed to prepare complete example with TABLE-PER-CLASS join strategy which does increment the sequence only once when you persist SubDepartment. Maybe it helps.
#Entity
#IdClass(CompoundPK.class)
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Department {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XXX")
#SequenceGenerator(name = "XXX", sequenceName = "XXX", allocationSize = 1)
#Id
private Long id;
#Id
private Long version;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
}
#Entity
public class SubDepartment extends Department {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class CompoundPK implements Serializable {
private Long id;
private Long version;
public CompoundPK() {
}
public CompoundPK(Long id, Long version) {
this.id = id;
this.version = version;
}
public Long getId() {
return id;
}
public Long getVersion() {
return version;
}
// hashCode & equals
}

How to not inherite Id GeneratedValue in hibernate (disable #GeneratedValue in child class)

I have a hibernate entity Super Class:
#MappedSuperclass
public abstract class Pojo_Entity_SuperClass
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="ID", unique=true, nullable=false, precision=18, scale=0)
protected long id;
public Long getId() {return id;}
//Other entity fields and methods
}
Next I inherite other entity classes like this:
#Entity
#Table(name="USR")
public class Usr extends Pojo_Entity_SuperClass
{
//Columns, fileds and others
}
But in some cases I want to inherit entity with "id" field without #GeneratedValue annotation.
The question is - how to disable #GeneratedValue annotation for id in child class ?
You can simply move the #Id from the base class to the sub-classes and then decide the generation strategies.
So you can have:
#MappedSuperclass
public abstract class Pojo_Entity_SuperClass
{
public abstract Long getId();
public abstract void setId(Long id);
//Other entity fields and methods
}
#Entity
#Table(name="USR")
public class Usr extends Pojo_Entity_SuperClass {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="ID", unique=true, nullable=false, precision=18, scale=0)
protected long id;
}
#Entity
#Table(name="ADMIN")
public class Admin extends Pojo_Entity_SuperClass {
#Id
#SequenceGenerator(name = "ID_GENERATOR", sequenceName = "admin_id_seq")
#GeneratedValue(generator = "ID_GENERATOR")
#Column(name="ID", unique=true, nullable=false, precision=18, scale=0)
protected long id;
}
Is this what you need?
Alternatively, you perhaps actually don't want to avoid inheritance. I tried to do the same before I realized I wanted to create User entity with id from external system and force this id as id in my system. Since entities are otherwise created with our id, common ancestor with id and sequence generator is valid solution while User with external id would be nonsystematic.
Hence it was IMHO cleaner to generate id of User just as in any other case and add another column external_id to table and entity class.

Specifying distinct sequence per table in Hibernate on subclasses

Is there a way to specify distinct sequences for each table in Hibernate, if the ID is defined on a mapped superclass?
All entities in our application extend a superclass called DataObject like this:
#MappedSuperclass
public abstract class DataObject implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id")
private int id;
}
#Entity
#Table(name = "entity_a")
public class EntityA extends DataObject { ... }
#Entity
#Table(name = "entity_b")
public class EntityB extends DataObject { ... }
This causes all entities to use a shared sequence, the default hibernate_sequence.
What I would like to do is use a separate sequence for each entity, for example entity_a_sequence and entity_b_sequence in the example above. If the ID were specified on the subclasses then I could use the #SequenceGenerator annotation to specify a sequence for each entity, but in this case the ID is on the superclass. Given that ID is in the superclass, is there a way I can use a separate sequence for each entity — and if so, how?
(We are using PostgreSQL 8.3, in case that's relevant)
Have you tried doing it this way ?
#MappedSuperclass
public abstract class DataObject implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idgen")
#Column(name = "id")
private int id;
}
#Entity
#SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "entityaseq")
#Table(name = "entity_a")
public class EntityA extends DataObject {
}
#Entity
#SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "entitybseq")
#Table(name = "entity_b")
public class EntityB extends DataObject {
}
I'm sorry I don't have the required environment to test it right now but I'll try it later.
We use this in the abstract superclass of all of our JPA entities:
#Id
#GeneratedValue(generator = "pooled")
#GenericGenerator(name = "pooled", strategy = "org.hibernate.id.enhanced.TableGenerator", parameters = {
#org.hibernate.annotations.Parameter(name = "value_column_name", value = "sequence_next_hi_value"),
#org.hibernate.annotations.Parameter(name = "prefer_entity_table_as_segment_value", value = "true"),
#org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled-lo"),
#org.hibernate.annotations.Parameter(name = "increment_size", value = "100")})
private Long id;
It's a bit verbose, but it allows setting the prefer_entity_table_as_segment_value which means you don't need to repeat the id field or the generator annotations in the subclasses.
I was not quite happy about the need to declare the sequence name on each class individually. I have checked the source code and came up with this solution:
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
// ...
#Id
#GeneratedValue(generator = "sequenceIdGenerator")
#GenericGenerator(
name = "sequenceIdGenerator",
strategy = "sequence",
parameters = #Parameter(
name = SequenceStyleGenerator.CONFIG_PREFER_SEQUENCE_PER_ENTITY,
value = "true"))
#Column(updatable = false, nullable = false)
protected Long id;
IHMO there is better way to do this:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
It works in my app.
TABLE generation stretergy uses separate db sequence for each table but it is little expensive operation

Categories

Resources