I'm trying to create JPA entities by using inheritance , I am not using any JPA polymorphic mechanism to do this. The reason is I want model classes to be independent, so if I want to use JPA I can extend the same model classes and create JPA entities and get the job done. My question is, is this possible to achieve without using JPA polymorphic mechanism, because when I try to deal with the JPA entities created after extending the model classes I don't see the properties that are inherited from super class but I can see new properties in the table if I add new properties in to the extended JPA entity.
Here are my entities:
#Data
public abstract class AtricleEntity {
protected Integer Id;
protected String title;
protected Integer status;
protected String slug;
protected Long views;
protected BigDecimal rating;
protected Date createdAt;
protected Date updatedAt;
}
#Data
#Entity
#Table(name="articles_article")
#RequiredArgsConstructor
public class Article extends AtricleEntity {
public static final String TABLE_NAME = "articles_article";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer Id;
private String title;
}
#Repository
public interface ArticleRepository extends JpaRepository<Article, Integer>{}
I can see a table with a column title created if i run this. that's because I've explicitly added that property in Article , but i want other columns to appear in the table with the help of java inheritance. is this possible?
Simple answer is NO. JPA cannot use object's inheritance out of the box coz of the simple reason that other children will have different column names and other parameters and might choose not even to save these columns.
So JPA has it's own inheritance mappings which an object might have to follow. Usage like MappedSuperclass might help.
Reference : http://www.baeldung.com/hibernate-inheritance for hibernate.
#MappedSuperclass annotation put on your super class should help.
https://docs.oracle.com/javaee/5/api/javax/persistence/MappedSuperclass.html
Related
I am a relative newbie to JPA, and I've read books (Java Persistence with Hibernate, Pro JPA 2 - Mastering the Java Persistence API), done google searches, but I have not been able to come up with a solution to the following situation.
I have a base class called History, that has all the persistent information needed to store the class's data members to a database. However, the class has an abstract method that needs to be overridden in derived classes. The derived classes do not have any persistence information of their own. They exist solely for two reasons:
to uniquely implement the abstract method defined in the base
History class
to persist the data to it's own table
The code below should make this clear.
#??? What annotation should I use here?
public abstract class History
{
#Id #GeneratedValue
private int id; // primary key
#Lob #Column(columnDefinition="mediumtext", length=65535)
protected String string; // string containing history
public abstract String foo();
}
#Entity
#Table(name="derived_history_1")
public class Derived1 extends History
{
public String foo()
{
return "Hello";
}
}
#Entity
#Table(name="derived_history_2")
public class Derived2 extends History
{
public String foo()
{
return "World";
}
}
I didn't think that #Inheritance(strategy=InheritanceType.JOINED) made sense, because nothing is being inherited in the derived classes that needs to be made persistent.
I tried #MappedSuperclass, but then the CascadeType.PERSIST and CascadeType.MERGE did not work when the derived classes were data members of another class. For example,
#Entity
#Table(name="part")
public class Part
{
...
#OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, optional=false, fetch=FetchType.LAZY)
#JoinColumn(name="history_id") // foreign key into history_part table
protected Derived1 history;
}
So I couldn't find anything that worked and fit my situation.
I hope I'm explaining this well enough that people can understand.
Does anyone know how to do this that's not a complete and total hack :-)
Thanks for any help.
Following annotations should work:
#Entity
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
Inheritance type TABLE_PER_CLASS makes inheriting entities to create own table and you also need to tell that History is also an Entity even it does not have table of its own.
I have a set of Java classes with the following UML diagram:
public class Invoice {
#Id
private long id;
...
}
public class InvoiceDetail {
#Id
private long id;
...
private String productName;
private int quantity;
private double price;
}
My purpose is using JPA annotations to establish the different relationships between them. There is a composition relationship between Invoice and InvoiceDetail, which is resolved using #Embedded and #Embeddable annotations for Invoice and InvoiceDetail respectively. However, a problem appears by establishing the relationships between InvoiceDetail, Class3 and Class4. In these relationships InvoiceDetail must be annotated as #Entity. However, when a class is annotated at the same time as #Entity and #Embeddable, the corresponding server will throw a runtime error during the deployment.
Basing on the information of this website, I have written the following possible solution:
#Entity
public class Invoice {
#Id
private long id;
...
#ElementCollection
#CollectionTable(name="INVOICEDETAIL", joinColumns=#JoinColumn(name="INVOICE_ID"))
private List<InvoiceDetail> invoiceDetails;
...
}
Would be this right in order to resolve my problem?
Thanks in advance.
Although without knowing what the classes really are it is hard to tell, I suppose that you have a design problem. The composition between Class1 and Class2 says that any Class2 instance only exists within the lifecycle of a corresponding Class1 instance. But on the other hand you have Class3 instances and Class4 instances which can / must have a relationship to a Class2 instance.
What I'm trying to say is that from my point of view the relationship between Class1 and Class2 should be a simple association and not a composition. Following this path Class2 would be an Entity in JPA and then you should have your problem solved.
I usually use #Embeddable for classes whose instances never exist by themselfes and #Entity for any class whose instances can exist without other instances. An address for example could be implemented either way but not on the same system. Address would be #Embeddable if I don't want to link addresses but it had to be #Entity if I want to make sure the same address isn't saved in more than one row.
[edit: added after classes 1 and 2 were renamed to Invoice and InvoiceDetails]
Having a composition between Invoice and InvoiceDetails makes perfect sense. But I still think you should avoid the need of double personality for InvoiceDetails. I can think of two solutions (both refactorings):
If you prefer having InvoiceDetails as #Embeddable you could change the associations of Class3 and Class4 to Invoice instead of InvoiceDetails. InvoiceDetails would still be traversable via the Invoice object.
If you prefer keeping the associations as is you could declare InvoiceDetails to be an entity. You could still achieve your composition with a cascading delete (see javax.persistence.CascadeType). As it seems that InvoiceDetails already has it's own table, this probably is the better option.
I checked my JPA applications and haven't found any occurence of the same class being #Entity and #Embeddable. Honestly, I doubt if this is possible at all because the official javadoc of #Embeddable says:
Specifies a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity.
As #Entity has it's own identity, you would try to declare the same object having two identities - and this can't work.
[/edit]
[edit2: adding code for solution proposal #2]
This code should work with some assumptions (see below). This is the implementation of bi-directional navigation for a 1:n-relationship.
#Entity
public class Invoice {
#Id
private long id;
#OneToMany(mappedBy="invoice", cascade = CascadeType.ALL)
private List<InvoiceDetail> details;
}
#Entity
public class InvoiceDetails {
#Id
private long id;
#ManyToOne
#JoinColumn(name="invoice_id")
private Invoice invoice;
}
Assumptions: Tables are named like the entities, the foreign key column for invoice_details table is named "invoice_id" and both tables have a primary key column named "id". Note that the mappedBy-value "invoice" refers to the entity field while the name-value "invoice_id" refers to the database table.
Be cautious when deleting an Invoice object whose InvoiceDetails still are referenced by your Class3 or Class4 instances - you have to release these references first.
For information about JPA refer to these resources:
The Java EE 7 Tutorial: Persistence
Wikibooks: Java Persistence
Javadoc of Package javax.persistence
[/edit]
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
I wanted to know if there is a way to get in a One2Many relationship a field of the One side that is an aggregate of the Many side.
Let's take the following example:
#Entity
public class A {
#Id
private Long id;
#OneToMany (mappedBy="parentA")
private Collection<B> allBs;
// Here I don't know how to Map the latest B by date
private B latestB;
// Acceptable would be to have : private Date latestBDate;
}
#Entity
public class B {
#Id
private Long id;
private Date date;
#ManyToOne (targetEntity=A.class)
private A parentA;
}
My question is how can I make the mapping of the field latestB in the A entity object without doing any de-normalization (not keeping in sync the field with triggers/listeners)?
Perhaps this question gives some answers, but really I don't understand how it can work since I still want to be able to fetch all childs objects.
Thanks for reading/helping.
PS: I use hibernate as ORM/JPA provider, so an Hibernate solution can be provided if no JPA solution exists.
PS2: Or just tell me that I should not do this (with arguments of course) ;-)
I use hibernate as ORM/JPA provider, so an Hibernate solution can be provided if no JPA solution exists.
Implementing the acceptable solution (i.e. fetching a Date for the latest B) would be possible using a #Formula.
#Entity
public class A {
#Id
private Long id;
#OneToMany (mappedBy="parentA")
private Collection<B> allBs;
#Formula("(select max(b.some_date) from B b where b.a_id = id)")
private Date latestBDate;
}
References
Hibernate Annotations Reference Guide
2.4.3.1. Formula
Resources
Hibernate Derived Properties - Performance and Portability
See,
http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Filtering.2C_Complex_Joins
Basically JPA does not support this, but some JPA providers do.
You could also,
- Make the variable transient and lazy initialize it from the OneToMany, or just provide a get method that searches the OneToMany.
- Define another foreign key to the latest.
- Remove the relationship and just query for the latest.
I need to create a relation in Hibernate, linking three tables: Survey, User and Group.
The Survey can be visible to a User or to a Group, and a Group is form of several Users.
My idea was to create a superclass for User and Group, and create a ManyToMany relationship between that superclass and Survey.
My problem is that Group, is not map to a table, but to a view, so I can't split the fields of Group among several tables -which would happen if I created a common superclass-.
I thought about creating a common interface, but mapping to them is not allowed.
I will probably end up going for a two relations solution (Survey-User and Survey-Group), but I don't like too much that approach.
I thought as well about creating a table that would look like:
Survey Id | ElementId | Type
ElementId would be the Group or UserId, and the type... the type of it.
Does anyone know how to achieve it using hibernate annotations? Any other ideas?
Thanks a lot
I posted a very similar answer yesterday. To summarize, you can't use a mapped superclass because a mapped superclass is not an entity and can't be part of an association (which is what you want) but you can use an abstract Entity with a TABLE_PER_CLASS inheritance strategy to obtain a similar result.
Something like this (not tested):
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractEntity {
#Id #GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
#ManyToMany(mappedBy="entities")
private Set<Survey> surveys = new HashSet<Survey>();
...
}
#Entity
public class User extends AbstractEntity {
...
}
#Entity
public class Group extends AbstractEntity {
...
}
#Entity
public class Survey {
#Id #GeneratedValue
private Long id;
#ManyToMany
private Set<AbstractEntity> entities = new HashSet<AbstractEntity>();
...
}
References
Annotations, inheritance and interfaces
using MappedSuperclass in relation one to many
Polymorphic association to a MappedSuperclass throws exception
You can use the table per concrete class inheritance strategy, hibernate will replicate all properties for each subclass, this will work with a view.
I would also suggest the composite pattern for users/groups (which is close to your first option).
http://en.wikipedia.org/wiki/Composite_pattern
This is possible. Such an 'inherited properties' approach can be achieved by defining the superclass as a MappedSuperclass.
EDIT:
There is also some alternatives listed in section 2.2.4 in the hibernate annotations reference doc, section 2.2.4.4 covers MappedSuperclass.