Lets say I have the following POJO:
public class MyThing {
private int myNumber;
private String myData;
//assume getter/setter methods
}
Is it now possible to extend this POJO as a JPA entity?
#Entity
#Table(name = "my_thing")
public class MyThingEntity extends MyThing implements Serializable {
#Column(name = "my_number")
//?????????
#Column(name = "my_data")
//????????
}
I want to keep the POJO separate from the JPA entity. The POJO lives in a different project and is often used without a persistence layer, my project wants to persist it in a database and do so without the overhead of mapping from a POJO to an entity and back.
I understand that JPA entities are POJOs, but in order to use it I would have to include a library that implements javax.persistence and the other projects using the same base object have no use for a persistence layer.
Is this possible? Is this a good idea?
JPA specification states
Entities may extend non-entity classes as well as entity classes, and non-entity classes may extend entity classes.
#javax.persistence.MappedSuperclass annotation allows you to define this kind of mapping
#MappedSuperclass
public class MyThing implements Serializable {
private int myNumber;
private String myData;
// getter's and setter's
}
And
#Entity
#Table(name="MY_THING")
public class MyThingEntity extends MyThing {
}
As said by JPA specification
The MappedSuperclass annotation designates a class whose mapping information is applied to the entities that inherit from it.
And
A class designated with the MappedSuperclass annotation can be mapped in the same way as an entity except that the mappings will apply only to its subclasses since no table exists for the mapped superclass itself.
If you need to override some property defined by MyThing, use #AttributeOverride (when you want to override a single property) or #AttributeOverrides (when you want to override more than one property)
#Entity
#Table(name="MY_THING")
#AttributeOverride(name="myData", column=#Column(name="MY_DATA"))
public class MyThingEntity extends MyThing {
}
And
#Entity
#Table(name="MY_OTHER_THING")
#AttributeOverrides({
#AttributeOverride(name="myData1", column=#Column(name="MY_DATA_1")),
#AttributeOverride(name="myData2", column=#Column(name="MY_DATA_2"))
})
public class MyOtherThingEntity extends MyThing {
}
If you do not want to change your base class, you can use xml to define it as a #MappedSuperClass
Be aware: by default, the persistence provider will look in the META-INF directory for a file named orm.xml
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
<mapped-superclass class="MyThing">
</mapped-superclass>
</entity-mappings>
Nothing else. If you want to override a property, use #AttributeOverride as shown above
It is possible:
you can map it with XML - make an orm.xml (conforming to the orm schema), and map the columns of your POJO, without even extending it. It will be JPA-enabled in one environment, and a POJO in the other one
override just the getter methods and annotate them - (I'm not sure if this will work)
That said, I don't think it is necessary to do this. Just annotate your POJO, and add the compile-time dependency to your projects. Then each project will decide whether it will use them as JPA entities or not.
Related
I need to generify an interface to a class that is annotated to a specific annotation, say having the following entity class
#Entity
#Audited
class Record {
private Long id;
private String something;
private String somethingElse;
}
which is audited with Hibernate Envers, I want to provide a service class that obtains some revision data. With something like
public interface AuditRecordService<E extends Audited> {
//
}
I know I can modify the Record class to extend an abstract class, something like:
#Entity
#Audited
class Record extends RevisionedEntity {
...
This works for me, but I want to avoid unnecessary extension, since it's already annotated with #Audited. Is it possible to reuse this annotation as a generic type?
Audited is an annotation, not a type. Annotations cannot be extended, so the only possible implementation of AuditRecordService<E extends Audited> would be AuditRecordService<Audited>, which would be pretty useless.
We have an abstract #MappedSuperClass and bunch of entities extending it, like:
#MappedSuperclass
public abstract class SuperEntity implements Serializable {
#Id
private Long id;
private String name;
}
and lots of entities like:
#Entity
public class Sub[1..20]Entity extends SuperEntity {
...
}
Because of this there were created - as well - a bunch of repositories for each entity. All well this far.
Now there is a need to fetch all the entities that extend super. Therefore SuperEntity was changed as below:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class SuperEntity implements Serializable {
This should be functionally almost the same (is it?).
Then a new repository for this was created, like:
public interface SuperEntityRepository extends JpaRepository<SuperEntity, Long> { };
Now the problem is, when calling:
superEntityRepository.findAll();
it returns only about 5 of sub entities not all the 20. What could be wrong?
Upon writing the question I realized what was the problem. Values - including IDs - were inserted straight to the database and IDs were not unique in the scope of SuperEntity. That is why there is no #GeneratedValue, BTW. IDs were only unique in the scope of each extending sub class entity.
There were no error messages. Spring repository just picked up the first found id and all the other entities with same ID were ignored.
So the answer to have this working is to to update all the extending entities to have unique ID in the scope of the SuperEntity.
However, updating references cascading is quite a job so if there is a lighter way to get this working, share it.
Yes, I could have deleted the question but maybe someone finds it and this answer useful
I'm going to create a model that implement inheritance concept. I was thinking that it is possible by creating two (or more) tables (one for the parent class and the other for the child class), then create two (or more) model based on the table.
I currently created a model that acts as a parent class, and made it abstract
#NoArgsConstructor // lombok
#AllArgsConstructor // lombok
#Data // lombok
#Entity(name="Account")
#Inheritance
public abstract class AccountModel {
#Id
#Column(name="username")
private String username;
// Some other fields and getters and setters here
}
and then created child class that extends above class
#NoArgsConstructor // lombok
#Data // lombok
#EqualsAndHashCode(callSuper=true) // lombok
#Entity(name="Administrator")
public class AdministratorModel extends AccountModel {
#Id
#Column(name="username")
private String username;
// some other fields and getters and setters here
}
(currently, the username is used as the join)
and I created two repositories for both models
#Repository
public interface AccountRepository extends JpaRepository<AccountModel, String>{};
#Repository
public interface AdministratorRepository extends JpaRepository<AdministratorModel, String>{};
Then, I tested it by trying to save new AdministratorModel object to AdministratorRepository by using JpaRepository.save() method.
I was expecting that this setting will fill data from the object to both of the tables on the database, and automatically mapped all properties to each table. but, the data is only saved as one record on the parent table, and adding new column (one column is something that may refer to child table, and other column is properties of the child table, without adding the join column 'username'), while leaving the child table empty.
I think that I'm doing it wrong.
Then, how to make it works as expected ?
Should I not used inheritance and save the model manually using two (or more) repositories, or should I only create one repository with a custom query, or is there any other way ?
This kind of inheritance should add non default strategy to #Inheritance annotation.
Changing #Inheritance to #Inheritance(strategy=InheritanceType.JOINED) fixes the problem.
As the documentation says this strategy is:
A strategy in which fields that are specific to a
subclass are mapped to a separate table than the fields
that are common to the parent class, and a join is
performed to instantiate the subclass.
Let's suppose I have a JPA entity:
#Entity
#Table(name = "PARENT")
public class Parent {
// ...
}
Is there any way, maybe Hibernate-specific, to create subclass of Parent in a separate table?
#Entity
#Table(name = "CHILD")
public class Child extends Parent {
// ...
}
The main idea is to have set of common entity classes in a base package shared among projects, and extend them only if some project-specific properties are required.
Hibernate Inheritance: Annotation Mapping
Annotate the parent class with #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS). The Hibernate docs (for version 4.3, the new 5.0 docs seem to be missing this section so far) cover this in Chapter 10 and section 5.1.6 of the manual.
In One Table per Concrete class scheme, each concrete class is mapped as normal persistent class. Thus we have 3 tables; PARENT, CHILD to persist the class data. In this scheme, the mapping of the subclass repeats the properties of the parent class.
Following are the advantages and disadvantages of One Table per Subclass scheme.
Advantages
This is the easiest method of Inheritance mapping to implement.
Following is the example where we map Parent and Child entity classes using JPA Annotations.
#Entity
#Table(name = "Parent")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Parent {
// Getter and Setter methods,
}
#Inheritance – Defines the inheritance strategy to be used for an entity class hierarchy. It is specified on the entity class that is the root of the entity class hierarchy.
#InheritanceType – Defines inheritance strategy options. TABLE_PER_CLASS is a strategy to map table per concrete class.
#Entity
#Table(name="Child")
public class Child extends Parent {
// Getter and Setter methods,
}
Annotate the parent class with #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS). The Hibernate docs (for version 4.3, the new 5.0 docs seem to be missing this section so far) cover this in Chapter 10 and section 5.1.6 of the manual.
Is it possible to make inheritance in JPA/Hibernate without id?
My use case:
I have multiple entities and I want every time change is being done, timestamp being recorded. So I created AbstractResource and want each derived class inherit properties and logic (to avoid writing same stuff over and over again in each class).
My problem that hibernate wants an ID to entity, and I do not care about id, since my only concern is additional properties. And each entity can have whatever id it wants (String, int, long, different name, etc.).
I tried with Embeddable, but looks like hibernate does not support inheritance for Embeddable. Do you have any ideas, how my task can be achieved?
My parent class from which "Audited" entities are derived:
#Embeddable
#EntityListeners(AbstractResourceListener.class)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class AbstractResource {
private long modifyTimestamp;
#Column(name = "_MODIFY_TIMESTAMP", nullable = true)
public long getModifyTimestamp() {
return modifyTimestamp;
}
public void setModifyTimestamp(long modifyTimestamp) {
this.modifyTimestamp = modifyTimestamp;
}
}
#MappedSuperclass is an annotation for super classes that you can extend and use in audit. Please see example