Is there any reason why shouldn't all my entities be subclasses of one generic ModelEntity object?
#Entity
public class ModelEntity {
#Id Long id;
}
#Subclass
public class User extends ModelEntity {
#Index
String username;
}
The advantages are clear: there is code common to all entities (like id, date, getKey)
Can you think of disadvantages?
It can be helpful to have a common base class, but you almost certainly do not want to make it part of a polymorphic entity hierarchy. Don't use #Subclass for this purpose; you don't need it:
public class ModelEntity {
#Id Long id;
}
#Entity
public class User extends ModelEntity {
#Index
String username;
}
Well, one of the great advantages of the jpa abstractions is to have insulation between the persistence layer and business logic. If you use an hidden id for all your entities you are giving up on that.
For example you could have a value object with your implementation so that you are actually hiding the #Id part of your entity. You could the use a completely different #Id for "real" entities.
Related
I have a class Model
public abstract class Model {
#PrimaryKey
#NonNull
public String id;
}
and sub-class FooModel
#Entity
public FooModel extends Model {
String name;
}
I'd like to mark id as autoincrement but only in the child FooModel using #PrimaryKey(autoGenerate = true)
How can I go about this?
from my understanding room just as most other ORM frameworks does not realy handle class inheritance very well. you may consider defining your two classes as separate models in order to maximise on the full functionality of room .
I am creating entities that are the same for two different tables. In order do table mappings etc. different for the two entities but only have the rest of the code in one place - an abstract superclass. The best thing would be to be able to annotate generic stuff such as column names (since the will be identical) in the super class but that does not work because JPA annotations are not inherited by child classes. Here is an example:
public abstract class MyAbstractEntity {
#Column(name="PROPERTY") //This will not be inherited and is therefore useless here
protected String property;
public String getProperty() {
return this.property;
}
//setters, hashCode, equals etc. methods
}
Which I would like to inherit and only specify the child-specific stuff, like annotations:
#Entity
#Table(name="MY_ENTITY_TABLE")
public class MyEntity extends MyAbstractEntity {
//This will not work since this field does not override the super class field, thus the setters and getters break.
#Column(name="PROPERTY")
protected String property;
}
Any ideas or will I have to create fields, getters and setters in the child classes?
Thanks,
Kris
You might want to annotate MyAbstractEntity with #MappedSuperclass class so that hibernate will import the configuration of MyAbstractEntity in the child and you won't have to override the field, just use the parent's. That annotation is the signal to hibernate that it has to examine the parent class too. Otherwise it assumes it can ignore it.
Here is an example with some explanations that may help.
#MappedSuperclass:
Is a convenience class
Is used to store shared state & behavior available to child classes
Is not persistable
Only child classes are persistable
#Inheritance specifies one of three mapping strategies:
Single-Table
Joined
Table per Class
#DiscriminatorColumn is used to define which column will be used to distinguish between child objects.
#DiscriminatorValue is used to specify a value that is used to distinguish a child object.
The following code results in the following:
You can see that the id field is in both tables, but is only specified in the AbstractEntityId #MappedSuperclass.
Also, the #DisciminatorColumn is shown as PARTY_TYPE in the Party table.
The #DiscriminatorValue is shown as Person as a record in the PARTY_TYPE column of the Party table.
Very importantly, the AbstractEntityId class does not get persisted at all.
I have not specified #Column annotations and instead are just relying on the default values.
If you added an Organisation entity that extended Party and if that was persisted next, then the Party table would have:
id = 2
PARTY_TYPE = "Organisation"
The Organisation table first entry would have:
id = 2
other attribute value associated specifically with organisations
#MappedSuperclass
#SequenceGenerator(name = "sequenceGenerator",
initialValue = 1, allocationSize = 1)
public class AbstractEntityId implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "sequenceGenerator")
protected Long id;
public AbstractEntityId() {}
public Long getId() {
return id;
}
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "PARTY_TYPE",
discriminatorType = DiscriminatorType.STRING)
public class Party extends AbstractEntityId {
public Party() {}
}
#Entity
#DiscriminatorValue("Person")
public class Person extends Party {
private String givenName;
private String familyName;
private String preferredName;
#Temporal(TemporalType.DATE)
private Date dateOfBirth;
private String gender;
public Person() {}
// getter & setters etc.
}
Hope this helps :)
Mark the superclass as
#MappedSuperclass
and remove the property from the child class.
Annotating your base class with #MappedSuperclass should do exactly what you want.
This is old, but I recently dealt with this and would like to share my solution. You can add annotations to an overridden getter.
#MappedSuperclass
public abstract class AbstractEntity<ID extends Serializable> implements Serializable {
#Column(name = "id", nullable = false, updatable = false)
#Id
private ID id;
public ID getId() {
return id;
}
...
}
#Entity
#Table(name = "address")
public final class Address extends AbstractEntity<UUID> implements Serializable {
...
#Override
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
public final UUID getId() {
return super.getId();
}
...
}
I have an entity that is super class
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#Table(name = "super_class")
public abstract class SuperClass implements Serializable {
#Transient
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private long id;
public abstract void initDefaultValues();
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
and some subclasses that extend the SuperClass.
#Entity
#Table(name = "Subclass1")
public class Subclass1 extends SuperClass{
private static final Logger log = LogManager
.getLogger(Subclass1.class);
#Transient
private static final long serialVersionUID = 1L;
// testcase configuration tab
private String configurationTabTestServer;
private String umtsRelease;
}
The other classes look the same.
I used to have them SINGLE_TABLE for inheritance type but we wanted each concrete class to have each own table. Because of TABLE_PER_CLASS I had to use GenerationType.TABLE.
I also have an entity class that has a foreign key to the super class
#Entity
#Table(name="myother_entity")
class Entity1{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#OneToOne(cascade = CascadeType.ALL)
private SuperClass superclass;
//more fields
}
I used an abstract class because I have one Entity1 class that could have different type of Superclass. We didn't want to create different Entity1 and Entity2 and Entity3 etc classes for each subclass. So we created one Entity1 class that can have a field of type SuperClass, that could point to any of the subclasses.
On my program I create many Entity1 intances that some of them that have different type of superclass as field value. Each could be of type subclass1 or subclass2 etc. At first we used to have one single table for all subclasses. Everything worked fine. But after we decided to split our tables this is what it happens. When I edit any Entity1 instance, that has already SuperClass field set(using one of the sub classes), and save it (merging it) then it creates a new instance of my Subclass associated with my Entity1 instance, and then saves it to the database. So I have two records now on the table of the subclass. This didn't happen when we used a SINGLE_TABLE inheritance type. Is this normal behaviour for JPA and hibernate?
Please, first consider this: DiscriminatorColumn and DiscriminatorValue annotations are specific to single-table approach. So they aren't to be used in table-per-class mappings.
Now, let's go to the issue:
In table-per-class mapping, there will be two records with same ID: one in a parent table, other in a child table.
As I understood, in your case, two records are being written in the child table, right? If so, the problem must be when you load the Entity1 data from the database. The property "superclass" must have its ID set. You can use eager or lazy loading for this. And check if that property is properly loaded (in debug mode) with its correct ID set before saving it.
Another way is to disable "cascade persist/merge" and to save the entities separately. It can provide more security to your data.
You can find more information here: http://docs.oracle.com/javaee/6/tutorial/doc/bnbqn.html
I have the following setup with Spring Data JPA and Hibernate as the persistence provider. All of my entities inherit from a base class
#MappedSuperclass
public class BaseEntity {
#Id
private id;
#Version
private String version;
//more common fields
}
For example:
#Entity
public class Foo extends BaseEntity {
}
This leads to a primary key column with name "ID" to be generated on the "FOO" table. I would like to change the naming of the primary key column. It should reflect the name of class or table. So it should be "FOO_ID" instead of just "ID".
I know that I could do this statically by using #Column(name = "FOO_ID"). But that would mean I have to do this for every Entity. Is there a more dynamic way to achieve this?
I know this is an old question, but stumbled across this looking for an answer... Eventually found this solution elsewhere:
#Entity
#AttributeOverride(name="id", column=#Column(name="FOO_ID"))
public class Foo extends BaseEntity {
}
All your subClasses will have the same ID column name because of the inheritance, you can specify a common id colum name for all subClasses in the Base entity Class
Why use inheritance then? Just do it without inheritance.
You could use getters/setters to rename your fields
Ex:
class Foo {
private Long id;
public Long getFooId() {
return this.id;
}
public void setFooId(Long fooId) {
this.id = fooId;
}
}
I'm considering using Annotations to define my Hibernate mappings but have run into a problem: I want to use a base entity class to define common fields (including the ID field) but I want different tables to have different ID generation strategies:
#MappedSuperclass
public abstract class Base implements Serializable {
#Id
#Column(name="ID", nullable = false)
private Integer id;
public Integer getId(){return id;}
public void setId(Integer id){this.id = id;}
...
}
#Entity
#Table(name="TABLE_A")
public class TableA extends Base {
// Table_A wants to set an application-defined value for ID
...
}
#Entity
#Table(name="TABLE_B")
public class TableB extends Base {
// How do I specify #GeneratedValue(strategy = AUTO) for ID here?
...
}
Is there some way to do this? I've tried including the following into TableB but hibernate objected to my having the same column twice and it seems wrong:
#Override // So that we can set Generated strategy
#Id
#GeneratedValue(strategy = AUTO)
public Integer getId() {
return super.getId();
}
In the code above, it looks like you're mixing annotations on fields (superclass) and methods (subclass). The Hibernate reference documentation recommends avoiding this, and I suspect it might be causing the problem. In my experience with Hibernate, it's safer and more flexible to annotate getter/setter methods instead of fields anyway, so I suggest sticking to that design if you can.
As a solution to your problem, I recommend removing the id field from your Base superclass altogether. Instead, move that field into the subclasses, and create abstract getId() and setId() methods in your Base class. Then override/implement the getId() and setId() methods in your subclasses and annotate the getters with the desired generation strategy.
Hope this helps.
On the method in the child dont add the second #Id tag.
#Override // So that we can set Generated strategy
#GeneratedValue(strategy = AUTO)
public Integer getId() {
return super.getId();
}
My resolution:
Refactor the Base class into:
#MappedSuperclass
abstract class SuperBase<K> {
public abstract K getId();
}
#MappedSuperclass
class Base<K> extends SuperBase<K> {
#Id #GeneratedValue(AUTO)
public K getId() { ... }
}
Then, you can extends from Base for most of your entity classes, and if one needs to override the #GeneratedValue, just extend from SuperBase and define it.
If you put your annotations on the getter rather than the field, when you override the method in the subclass, the annotations placed there will be used rather than the ones in the superclass.