I’m trying to map the inheritance from the superclass LendingLine and the subclasses Line and BlockLine. LendingLine has an ManyToOne association with Lending.
When I try to get the LendingLines from the database without the inheritance it works fine. The association works also. But when i add the inheritance, lendingLines in Lending is empty. I also can't get any LendingLines from the DB with the inheritance.
Can anybody help me?
(Sorry for the bad explanation)
Thanks in advance!
LendingLine:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE")
#DiscriminatorValue(value="Line")
#Table(name = "LendingLine")
public class LendingLine {
...
public LendingLine(){}
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER, targetEntity=Lending.class)
#JoinColumn(name = "LendingId")
private Lending lending;
...
Lending:
#Entity
#Table(name = "Lending")
public class Lending {
...
public Lending(){}
#OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER, mappedBy = "lending")
private List<LendingLine> lendingLines;
...
BlockDate:
#Entity
#DiscriminatorValue(value = "BlockLine")
public class BlockLine extends LendingLine {
public BlockLine(){
}
}
LendingLineRepository:
This class only reads from the db because the db was created by another application ( C#) where the objects are added to the db.
public class LendingLineRepository extends JpaUtil implement LendingLineRepositoryInterface {
#Override
protected Class getEntity() {
return LendingLine.class;
}
#Override
public Collection<LendingLine> findAll() {
Query query = getEm().createQuery("SELECT l FROM LendingLine l");
System.out.println(query.getResultList().size());
return (Collection<LendingLine>) query.getResultList();
}
Table LendingLine:
Choose your type of superclass according to your needs:
Concrete Class
public class SomeClass {}
Define your superclass as a concrete class, when you want to query it and when you use a new operator for further logic. You will always be able to persist it directly. In the discriminator column this entity has it's own name. When querying it, it returns just instances of itself and no subclasses.
Abstract Class
public abstract class SomeClass {}
Define your superclass as an abstract class when you want to query it, but don't actually use a new operator, because all logic handled is done by it's subclasses. Those classes are usually persisted by its subclasses but can still be persisted directly. U can predefine abstract methods which any subclass will have to implement (almost like an interface). In the discriminator column this entity won't have a name. When querying it, it returns itself with all subclasses, but without the additional defined information of those.
MappedSuperclass
#MappedSuperclass
public abstract class SomeClass {}
A superclass with the interface #MappedSuperclass cannot be queried. It provides predefined logic to all it's subclasses. This acts just like an interface. You won't be able to persist a mapped superclass.
For further information: JavaEE 7 - Entity Inheritance Tutorial
Original message
Your SuperClass LendingLine needs to define a #DiscriminatorValue as well, since it can be instantiated and u use an existing db-sheme, where this should be defined.
Related
In this question I am working with Hibernate 4.3.4.Final and Spring ORM 4.1.2.RELEASE.
I have an User class, that holds a Set of CardInstances like this:
#Entity
#Table
public class User implements UserDetails {
protected List<CardInstance> cards;
#ManyToMany
public List<CardInstance> getCards() {
return cards;
}
// setter and other members/methods omitted
}
#Table
#Entity
#Inheritance
#DiscriminatorColumn(name = "card_type", discriminatorType = DiscriminatorType.STRING)
public abstract class CardInstance<T extends Card> {
private T card;
#ManyToOne
public T getCard() {
return card;
}
}
#Table
#Entity
#Inheritance
#DiscriminatorOptions(force = true)
#DiscriminatorColumn(name = "card_type", discriminatorType = DiscriminatorType.STRING)
public abstract class Card {
// nothing interesting here
}
I have several types of cards, each extending the Card base class and the CardInstance base class respectivly like this:
#Entity
#DiscriminatorValue("unit")
public class UnitCardInstance extends CardInstance<UnitCard> {
// all types of CardInstances extend only the CardInstance<T> class
}
#Entity
#DiscriminatorValue("leader")
public class LeaderCardInstance extends CardInstance<LeaderCard> {
}
#Entity
#DiscriminatorValue("unit")
public class UnitCard extends Card {
}
#Entity
#DiscriminatorValue("leader")
public class LeaderCard extends AbilityCard {
}
#Entity
#DiscriminatorValue("hero")
public class HeroCard extends UnitCard {
// card classes (you could call them the definitions of cards) can
// extend other types of cards, not only the base class
}
#Entity
#DiscriminatorValue("ability")
public class AbilityCard extends Card {
}
If I add a UnitCardInstance or a HeroCardInstance to the cards collection and save the entity everything works fine.
But if I add a AbilityCardInstance to the collection and save the entity it fails with a org.hibernate.WrongClassException. I added the exact exception + message at the bottom of the post.
I read through some questions, and lazy loading seems to be a problem while working with collections of a base class, so here is how I load the User entity before adding the card and saving it:
User user = this.entityManager.createQuery("FROM User u " +
"WHERE u.id = ?1", User.class)
.setParameter(1, id)
.getSingleResult();
Hibernate.initialize(user.getCards());
return user;
The database entries for "cards"
The database entries for "cardinstances"
org.hibernate.WrongClassException: Object [id=1] was not of the specified subclass [org.gwentonline.model.cards.UnitCard] : Discriminator: leader
Thanks in advance for any clues how to fix this problem. If you need additional information I will gladly update my question!
According to the first paragraph of the JavaDocs for #ManyToOne:
It is not normally necessary to specify the target entity explicitly since it can usually be inferred from the type of the object being referenced.
However, in this case, #ManyToOne is on a field whose type is generic and generic type information gets erased at the type of compilation. Therefore, when deserializing, Hibernate does not know the exact type of the field.
The fix is to add targetEntity=Card.class to #ManyToOne. Since Card is abstract and has #Inheritance and #DiscriminatorColumn annotations, this forces Hibernate to resolve the actual field type by all possible means. It uses the discriminator value of the Card table to do this and generates the correct class instance. Plus, type safety is retained in the Java code.
So, in general, whenever there is the chance of a field's type not being known fully at runtime, use targetEntity with #ManyToOne and #OneToMany.
I solved the problem.
The root cause lies in this design:
#Table
#Entity
#Inheritance
#DiscriminatorColumn(name = "card_type", discriminatorType = DiscriminatorType.STRING)
public class CardInstance<T extends Card> {
protected T card;
}
#Entity
#DiscriminatorValue("leader")
public class LeaderCardInstance extends CardInstance<LeaderCard> {
}
At runtime information about generic types of an class are not present in java. Refer to this question for further information: Java generics - type erasure - when and what happens
This means hibernate has no way of determining the actual type of the CardInstance class.
The solution to this is simply getting rid of the generic type and all extending (implementing) classes and just use one class like this:
#Table
#Entity
#Inheritance
#DiscriminatorColumn(name = "card_type", discriminatorType = DiscriminatorType.STRING)
public class CardInstance {
Card card;
}
This is possible (and by the way the better design) because the member card carries all the information about the card type.
I hope this helps folk if they run into the same problem.
I have an interface called Rule with 2 implementing classes who all share one Abstract base class.
#MappedSuperclass
public interface Rule { .. }
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseRule implements Rule {
#Entity
public class ImlementingRule1 extends BaseRule {
#Entity
public class ImlementingRule1 extends BaseRule {
I'm using this Rule interface in a containgRules class as such:
#OneToMany
#JoinColumn(name = "RULES_ID")
private List<Rule> rules;
Whatever setup I try I always end up with:
Caused by: org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: mynamespace.BaseRule
I personally have found no other solution than to use the abstract base class, instead of interface.
#OneToMany
#JoinColumn(name = "RULES_ID")
private List<BaseRule> rules;
It states right here:
Annotating interfaces is currently not supported.
I have a problem with JPA inheritance. See my entities below. I have a Person that can be in either a House or a Car, never at the same time of course. Both Car and House implement the PersonHoldable interface. I know I cannot map an Entity directly to an interface.
This is my model:
#Entity
public class Person{
private PersonHoldable personHoldable; // either a Car or a House
// This does not work of course because it's an interface
// This would be the way to link objects without taking JPA into consideration.
#OneToOne
public PersonHoldable getPersonHoldable() {
return this.personHoldable;
}
public void setPersonHoldable(PersonHoldable personHoldable) {
this.personHoldable = personHoldable;
}
}
#Entity
public class Car implements PersonHoldable{}
#Entity
public class House implements PersonHoldable{}
public interface PersonHoldable{}
How can I map this correctly in JPA taking the following into consideration?
I tried #MappedSuperclass on an abstract implementation of PersonHoldable. Although it will work for this particular setup, the problem with this is that Car and House in reality implement more interfaces. And they are mapped to other entities as well.
The Person could have a property for every possible PersonHoldable, so in this case it could have a getCar() and getHouse() property. That does not seem very flexible to me. If I would add a Bike implementation of the PersonHoldable I would have to change my Person class.
I can map the other way around, so having a OneToOne relation only on the PersonHoldable implementation side. This would mean adding a getPerson() property to the PersonHoldable. But then it's not very easy from a Person perspective to see what PersonHoldable it is linked to.
I'm using default JPA, so no Hibernate specific tags if possible.
If this is not possible with default JPA, what would be best practice in this case?
A slight variation on your second point would be to make Person have an inheritance type and implement a CarPerson and HousePerson (and later a BikePerson) whose whole purpose is to define the specific join relationship to a specific PersonHolder implementation. That keeps the relationship intact and more easily queryable from the Person side.
#Inheritance(strategy = JOINED)
#DiscriminatorColumn(name="holdableType", discriminatorType=CHAR, length=1)
#Entity
public class Person {
// common fields
}
#Entity
#DiscriminatorValue("C")
public class CarPerson extends Person {
#OneToOne
private Car car;
}
#Entity
#DiscriminatorValue("H")
public class HousePerson extends Person {
#OneToOne
private House house;
}
I am developing an application using Hibernate and am trying to model the following scenario:
I have an Activity Abstract class, defined as follows:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="activityType")
#Table(name = "BF_ACTIVITY")
public abstract class Activity extends PersistableObject {
#ManyToOne
#JoinColumn(name = "ASSIGNED_TO")
protected Contactable assignedTo;
#ManyToOne
#JoinColumn(name = "RAISED_BY")
protected Contactable raisedBy;
Note I am using Single Table inheritance (so all implementing objects will use the same table) and have set a DiscriminatorColumn.
Now I have two objects that extend Activity: ToDo and Status:
#Entity
#Table(name = "BF_TODO")
#DiscriminatorValue("Todo")
public class ToDo extends Activity {
...
#Entity
#Table(name = "BF_STATUS")
#DiscriminatorValue("Status")
public class Status extends Activity {
...
Again note that for both implementations i have set a DiscriminatorValue.
Finally, I want to have a Person object, and the person can have a list of Status and a list of ToDo - I also want to capture the bi-directional relationship, so am modelling it using the mappedBy configuration, but in both cases using the "raisedBy" field that exists in the super class "Activity":
public abstract class Person {
#ManyToMany(mappedBy="raisedBy", targetEntity=Activity.class)
private List<ToDo> todoItems = new ArrayList<ToDo>();
As i am using mappedBy with the member variable "raisedBy" from the super class I have also specified the targetEntity (otherwise it is not able to find the field in the ToDo object).
The problem is when I try to call getTodoItems() - it is actually just returning all "Activity" objects linked by "raisedBy" to the current person. e.g. it throws a cast exception because it is expecting the list of ToDos but Hibernate is returning Status objects in the list as well.
I was hoping the mappedBy config along with DiscriminatorValue would be enough to make this work - has anyone come across this or resolved it?
Thanks
EDIT
I have just found this post:
Can someone point me in the direction of a good #Where overview and example? could I just update my person as follows to use #Where with the discriminator column?
public abstract class Person {
#ManyToMany(mappedBy="raisedBy", targetEntity=Activity.class)
#Where(clause="activityType=Todo")
private List<ToDo> todoItems = new ArrayList<ToDo>();
Add the annotation :
#Where(clause = "activityType= 'Todo'")
But it's a hibernate annotation, not JPA
I have an abstract MappedSuperClass, Participant, which is extended by three kinds of 'Participant'. Each one then uses its own kind of 'Project', also an abstract MappedSuperClass. However, I want the base class to know about Projects so I can write generic code to interact with Participants. How do I specify this using Hibernate annotations? and how will I override it in the ExtendedParticipant and ExtendedProject classes?
Each Participant type, and each Project type, have their own database tables with existing data and ids (not unique across tables) that I cannot change.
The following code gives me the IDE error "Many to one attribute should not be 'Mapped Superclass'".
#MappedSuperclass
public abstract class Participant implements Persistable {
...
#ManyToOne
#JoinColumn(name = "project_id")
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
...
}
and the Project class is much the same with the same problem:
#MappedSuperclass
public abstract class Project implements Persistable {
...
#OneToMany
public List<Participant> getParticipants() {
return participants;
}
public void setProject(List<Participant> participants) {
this.participants = participants;
}
...
}
A mapped superclass is not an Entity, it can't be part of an association. So map your classes as entities and either introduce a mapped superclass "above" them or use a TABLE_PER_CLASS strategy.
See also
EclipseLink: Query to MappedSuperclass fails
Hibernate - Persisting polymorphic joins
Seems possible to have relations defined through the mappedsuperclass
according to the following
jboss_docs
another_stackoverflow_thread
object_db_doc
Docs said it's possible, but superclass isn't abstract in example
https://docs.oracle.com/javaee/5/api/javax/persistence/MappedSuperclass.html