Hibernate mapping annotation skipped by the system - java

I have an issue with the mapping under hibernate. I have an abstract class which implements an interface:
#MappedSuperclass
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractPromotion implements IPromotion {
}
This abstract class is the super class(as you can see with the annotation) and 3 mapped classes with #Entity extend this super class. When i launch a "maven install" i get this failure message inside the console , it says :
Caused by: org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: product.model.Product.promotion[product.promotion.AbstractPromotion]
i don't understand it because the class in question is mapped (as the classes which extend it) as above but it's like the annotations are skipped...
any help would be really appreciated
best regards

AbstractPromotion is not an entity. Its a MappedSuperclass. To apply an inheritance strategy, and to be the target of an association, a class must be an entity. Replace #MappedSuperclass by #Entity.
Mappedsuperclass is only used to be able to inherit common fields and methods in several, unrelated entities (like, for example, inherit an id, or a creationDate, in several unrelated entities).

If you want share the same database table for all the sublcass you need use discriminators.
In the main class you need to add this annotations.
#Entity
#Table(name = "foo")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "foo_type", discriminatorType = DiscriminatorType.STRING
And in the subclass this annotation
#Entity
#DiscriminatorValue("The value of your foo_type that discriminate this entity")

Related

Hibernate unable to determine collection owner while deleting from many-to-many relation with TABLE_PER_CLASS inheritance

Let's start with some context. I had to create separate module with some functionality, it was adding new entities which had many-to-many relation to entity defined in an abstract class. This abstract class was later to be extended in main project with Hiberante TABLE_PER_CLASS inheritance. The goal was to delegate as many responibilities to this module in which I could operate on an abstract class.
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractClassA {
...
#MappedBy("classAset")
#ManyToMany
private Set<ClassB> classBset = new HashSet<>();
}
#Entity
public class ClassB implements Serializable {
...
#ManyToMany
#JoinTable(name = "classB_classA_realtion_table",
joinColumns = {#JoinColumn(name = "classB_id")},
inverseJoinColumns = {#JoinColumn(name = "classA_id")})
private Set<AbstractClassA> classAset = new HashSet<>();
}
Most of it worked fine, the abstract class had some other relations (one-to-many) and there was no problems. I was also able to delete objects of ClassB without obstacles and faced issue only while trying to delete objects of a concreteClass extending said abstract class as I got error:
Caused by: org.hibernate.AssertionFailure: Unable to determine collection owner identifier for orphan-delete processing
I tried searching for answers but I couldn't find one that included many-to-many relation, all of them said about one-to-many and using orphanRemoval=true which is not possible here. I also tried experimenting with mappedBy but nothing seem to work.
As a last resort I removed the abstract class and made direct many-to-many relation with concreteClass extending it and that seemed to help. But that solution was contradicting the idea of moving functionality into separate module as now it had dependency to concreteClass.
I wonder is there something I'm missing in how I defined my relation or was my approach with using abstract class wrong from the beginning?

JPA entity inheritance without additional tables

I am working on a Maven Java web project based on Spring, JPA and Hibernate.
One part of this project shall be reused in another very similar project and gets therefore extracted as Maven module. This service and the corresponding entity are annotated like this:
#Service
public class MessageService
#Entity
public class Message
Both projects have similar but slightly different UserEntities.
#Entity
public class TypeAUser
#Entity
public class TypeBUser
The Message Entity has #OneToMany relationship to one of the UserEntities in each project.
I thought about a generic UserEntity but want to avoid creating additional tables as well as tables with fields of the "other" project.
Any ideas are appreciated.
Best regards,
Stefan
If you don't want to create additional tables, then you might want to consider using SINGLE_TABLE strategy.
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class UserEntity {
...
}
#Entity
public class TypeAUser extends UserEntity {
...
}
#Entity
public class TypeBUser extends UserEntity {
...
}
Well, when talking about Inheritance in Hibernate, you have three options:
Table per concrete class with unions
Table per class hierarchy(Single Table Strategy)
Table per subclass
Since you want to achieve it with one table, I suggest using option 2.
You need just a User table, with a USER_TYPE column to discriminate the user types ( Can be a number, varchar2, etc)
Then you need to create a class User with the following annotations:
You can specify a DiscriminatorColumn if you want, otherwise Hibernate will default to '{className}_TYPE
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="USER_TYPE", discriminatorType=DiscriminatorType.STRING)
public class User { .... }
In your concrete class implementations you can specify a Discriminator value (or if you don't, hibernate will default it to the class name ('TypeAUser'/ 'TypeBUser')
#Entity
#DiscriminatorValue('A')
public class TypeAUser
#Entity
#DiscriminatorValue('B')
public class TypeBUser

Any way to get fields from entity without actually joining into that table?

I'm not sure this is possible, but knowing just the very basics of JPA, I want to ask if it is possible. Basically I have an entity (We'll call it MyEntity) with a bunch of fields on it. We now want a 2nd entity that has all the same fields as MyEntity plus some of it's own. The use case for this is archiving these entities. We want to store all the archived entities in a separate table than MyEntity so that we don't have to qualify all the queries with archived=false. The JPA annotations for MyEntity look something like this:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE")
public abstract class MyEntity
{
....
There are multiple classes that extend this abstact class, each with #DiscriminatorValue annotations
For my archived entity (MyArchivedEntity) I want something along the lines of this:
#Entity
public class MyArchivedEntity
{
private MyEntity entity;
private String archiveSpecificField;
....
The problem with this of course is that it will want to join into the MyEntity table and get a specifc MyEntity record for populate the entity field. Is there some kind of annotation or something I can do to just get the same fields/columns from that entity (MyEntity) into this entity (MyArchivedEntity)?
Like I said in the beginning, I'm not sure if this is possible, but I hope I've explained well enough the end goal of what I'm trying to achieve, so that there could be some way to achieve it. If it makes any difference, I'm using PostgreSQL with EclipseLink.
What you can do is using #MappedSuperclass on a AbstractParentEntity becoming the super class of both MyEntity and MyArchiveEntity. So you will have something like the following:
#MappedSuperclass
public abstract class AbstractParentEntity {
public String someField;
...
}
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE")
public abstract class MyEntity extends AbstractParentEntity
{
//here you don't have any field (they all move to AbstractParentEntity
// (or, at least all the fields that need to be archivied are now declared in parent class)
....
}
#Entity
public class MyArchivedEntity extends AbstractParentEntity
{
private String archiveSpecificField;
....
More about MappedSuperclass here:
Mapped superclass inheritance allows inheritance to be used in the object model, when it does not exist in the data model. It is similar to table per class inheritance, but does not allow querying, persisting, or relationships to the superclass. Its' main purpose is to allow mappings information to be inherited by its' subclasses. The subclasses are responsible for defining the table, id and other information, and can modify any of the inherited mappings. A common usage of a mapped superclass is to define a common PersistentObject for your application to define common behavoir and mappings such as the id and version. A mapped superclass normally should be an abstract class. A mapped superclass is not an Entity but is instead defined though the #MappedSuperclass annotation or the <mapped-superclass> element.
You may wish to look into EclipseLink's history support. It can automatically maintain a historical archive table.
See,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/History
Another option would be to map the same classes in another persistence unit using an orm.xml to the archive tables.

JPA entity with a interface attribute, is it possible?

I have the following entity:
#Entity
public class TestCaseStep implements JPAEntity<Integer> {
...
#Column(name="STEP_NUMBER")
private Integer stepNumber;
#Enumerated(EnumType.STRING)
#Column(name="ACTION")
private Action action;
**#ManyToOne
#JoinColumn(name="connector")
private ScriptItem connector;**
My attribute ScriptItem is a interface for 3 other classes. Is it possible to configure JPA to set the correct class id in runtime execution?
Other resources:
public interface ScriptItem {
String getValue();
ScriptItemType getType();
}
#Entity
#Table(name="DAT_FEED_XML")
public class FeedXml implements JPAEntity<Integer>, ScriptItem {
...
}
#Entity
#Table(name="DAT_DB_STMT")
public class DbStatement implements JPAEntity<Integer>, ScriptItem {
...
}
Which annotations should I use to let JPA understand that I want to save the id of one of the 3 classes?
Thanks in advance,
It is really a good idea but unfortunately directly mapping interfaces as an entity attribute is not supported by JPA.
You can only map top level classes directly annotated with #Entity. This top level class may implement an interface though.
This feature has been requested and discussed for a long time.
Also take a look at this and this.
Depending on what you're trying to accomplish, #Inheritance annotation with table-per-class strategy could be an option.
I hope it helps.
It is possible with one caveat - you have to point JPA to a target entity which should be a concrete class. However, it can be an abstract class which implements your interface. So one principle of good design you'll have to break and in particular - "favour composition over inheritance".
Here's how to do it:
In your user class (which references your interface Task):
#OneToOne(targetEntity = BaseTask.class)
private Task task;
so here Task is an interface, but you have to declare an abstract class BaseTask.
In your BaseTask:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="task_type")
#Table(name="Task")
public abstract class BaseTask implements Task{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
Here the important thing is #DiscriminatorColumn - since all fields of the inheritance tree will be stored in 1 table (you specified that with the #Inheritance(strategy = InheritanceType.SINGLE_TABLE) annotation above. So this discriminator column will contain a label which will allow JPA to differentiate what kind of task you're talking about
Your concrete classes:
#Entity
#DiscriminatorValue("api")
public class ApiTask extends BaseTask {
or
#Entity
#DiscriminatorValue("ssh")
public class SshTask extends BaseTask{
As you can see the discriminator value tells JPA what task it is going to load (what class to instantiate).
No, not possible with JPA or Hibernate.
It does seem strange, when coding in the Java language which allows for attributes to be interfaces, that a persistence standard like JPA, intended for Java, does not support persisting attributes that are interfaces.
I always found it really very frustrating when my ORM would force me to refactor my 'pure' OO model just so that it could persist it.
It's not that it's technically impossible to implement persisting of interface attributes - in fact JDO has supported persistence of interfaces since forever which is why I started using it years ago for all of my own projects.
I've been tempted to switch to JPA, not because it is technically superior (in fact, quite the opposite) but just because of "herd mentality".
In recent contract work I have been forced to gain experience with JPA/Hibernate and in doing so, have lived out the many limitations and inefficiencies of that combination compared with JDO/DataNucleus. This was a great experience because it helped me quell my desire to join "the herd" :)
You need to setup your inheritance of ScriptItem correctly in JPA using whatever strategy you prefer (see the docs) and then JPA will be smart about it.

Get entity subclass without instanceOf

I have a scenario where I have a entity hierarchy structure implemented in hibernate.
It is InheritanceType.JOINED
Parent class:
#Entity
#Table(name = "LOY")
#Inheritance(strategy=InheritanceType.JOINED)
public class Loy implements Serializable
Child class boundary
#Entity
#Table(name = "LOY_BOUNDARY")
#PrimaryKeyJoinColumn(name="ID")
public class LoyBoundary implements Serializable
Child class percentage
#Entity
#Table(name = "LOY_PERCENTAGE")
#PrimaryKeyJoinColumn(name="ID")
public class LoyPercentage implements Serializable
I have a Customer entity class which is linked to the Loy entity class in a #ManyToOne.
The Customer can only be linked to one Loy at a time.
What I want to achieve is that I want to query the Customer class with unique id (passport number) and then get The Loy for the specific Customer through the #ManyToOne mapping in the Customer entity.
The problem that I'm sitting with is that I do not know which subclass of Loy is linked to the Customer.
I can go instanceOf to get the specific subclass but I want to try and avoid it.
I can also add a visitor pattern in the subclass entity, but not sure if this is best practice.
I would go with a visitor. Using instanceof won't work if the ManyToOne is lazy-loaded, because the actual type of the Loy won't be any of your subclasses, but a Hibernate proxy extending the Loy class. Indeed, Hibernate has no way to know, from the ID of the loy in the customer, which kind of Loy it refers to.
And a visitor is more OO and cleaner anyway.

Categories

Resources