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.
Related
I'm dealing with a couple of Entities with Tree like structures that were getting more complicated so I decided to create an abstract class for it so code was a bit more mainainable:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class TreeStructure<T extends TreeStructure>
{
#ManyToOne
protected T parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
protected Set<T> children = new HashSet<>();
//...
Then I have two Entities which extend it:
#Entity(name = "TreeStructureOne")
public class TreeStructureOne extends TreeStructure<TreeStructureOne>
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty("TreeStructureOne_id")
private long id;
And I basically want the database to be completely unaware of this TreeStructure abstraction and save all of the fields in each Entities tableand expected InheritanceType.TABLE_PER_CLASS to deal with that. But it seems I need to define the Id in the TreeStructure Entity at least or I get:
Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: TreeStructure
And I don't want to add an ID into the abstract class since this makes three tables in the database called: HT_TREE_STRUCTURE, HT_TREE_STRUCTURE_ONE and HT_TREE_STRUCTURE_TWO with one field ID each one.
Is there any solution to that?
Since TreeStructure is not an #Entity use only #MappedSuperclass
#MappedSuperclass
public abstract class TreeStructure<T extends TreeStructure> {
instead of #Entity and #Inheritance for the parent class.
You can find #MappedSuperclass in the Oracle JEE API documentation.
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.
I'm facing an issue with modelling hibernate mapping. Here is what i have:
#Entity
#Table
public class Entry {
#Id private long id;
#Embedded private Content content;
...
}
#MappedSuperclass
#DiscriminatorColumn(name="content_type")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Content {
#Column(name="content_type") private String type;
...
}
#Embeddable
#DiscriminatorValue("A")
public class AContent extends Content {
...
}
#Embeddable
#DiscriminatorValue("B")
public class BContent extends Content {
...
}
I'd like to have that all subclasses of Content to be mapped as embedded onto the Entry class.
In other words, in result i'd like to have one Entry table with columns from all subclasses of Content.
Currently the persisting Entry test says that:
javax.persistence.PersistenceException: org.hibernate.InstantiationException:
Cannot instantiate abstract class or interface: : foo.bar.Content
So it seems that loading fails because instead of getting AContent it tries to instantiate abstract Content.
Any ideas?
Spec says...
An entity may inherit from another entity class. Entities support inheritance, polymorphic associations and polymorphic queries.
It says nothing about embeddables being inheritable and thus has no support for inheritance for them.
I have a hierarchical JPA mapping that is several Classes deep. Something like this
#Entity
#Inheritance(strategy= InheritanceType.SINGLE_TABLE)
public abstract class BaseEntityClass implements Serializable {
// lots of stuff common to all my entities.
}
#Entity
#Inheritance(strategy= InheritanceType.TABLE_PER_CLASS)
public abstract class EntityTypeOne extends BaseEntityClass {
// stuff common to EntityTypeOne
}
#Entity
#Inheritance(strategy= InheritanceType.TABLE_PER_CLASS)
public abstract class EntityTypeTwo extends BaseEntityClass {
// stuff common to EntityTypeTwo
}
I know you use the #Inheritence method with the superclass to define the mapping strategy. But how does this work with deep hierarchies? I want all the leaf classes to be mapped to their own tables. Should I do SINGLE_TABLE with BaseEntityClass?
Your base class should be marked TABLE_PER_CLASS. Here's an example from OpenJPA:
#Entity
#Table(name="MAG")
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Magazine {
...
}
#Entity
#Table(name="TABLOID")
public class Tabloid
extends Magazine {
...
}
According to the JPA JavaDocs, the #Inheritance annotation should be specified on the root of the class hierarchy:
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.
It is not specified by the specification if this annotation can be placed on a subclass and as such its behavior is undefined.
So to answer the question you have asked in the comments, if you have this hierarchy:
SubSub -> Sub -> Base
You only need to annotate Base with #Inheritance(strategy = TABLE_PER_CLASS).
I want to persist my litte zoo with Hibernate:
#Entity
#Table(name = "zoo")
public class Zoo {
#OneToMany
private Set<Animal> animals = new HashSet<Animal>();
}
// Just a marker interface
public interface Animal {
}
#Entity
#Table(name = "dog")
public class Dog implements Animal {
// ID and other properties
}
#Entity
#Table(name = "cat")
public class Cat implements Animal {
// ID and other properties
}
When I try to persist the zoo, Hibernate complains:
Use of #OneToMany or #ManyToMany targeting an unmapped class: blubb.Zoo.animals[blubb.Animal]
I know about the targetEntity-property of #OneToMany but that would mean, only Dogs OR Cats can live in my zoo.
Is there any way to persist a collection of an interface, which has several implementations, with Hibernate?
JPA annotations are not supported on interfaces. From Java Persistence with Hibernate (p.210):
Note that the JPA specification
doesn’t support any mapping annotation
on an interface! This will be resolved
in a future version of the
specification; when you read this
book, it will probably be possible
with Hibernate Annotations.
A possible solution would be to use an abstract Entity with a TABLE_PER_CLASS inheritance strategy (because you can't use a mapped superclass - which is not an entity - in associations). Something like this:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractAnimal {
#Id #GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
...
}
#Entity
public class Lion extends AbstractAnimal implements Animal {
...
}
#Entity
public class Tiger extends AbstractAnimal implements Animal {
...
}
#Entity
public class Zoo {
#Id #GeneratedValue
private Long id;
#OneToMany(targetEntity = AbstractAnimal.class)
private Set<Animal> animals = new HashSet<Animal>();
...
}
But there is not much advantages in keeping the interface IMO (and actually, I think persistent classes should be concrete).
References
Annotations, inheritance and interfaces
using MappedSuperclass in relation one to many
Polymorphic association to a MappedSuperclass throws exception
I can guess that what you want is mapping of inheritance tree.
#Inheritance annotation is the way to go.
I don't know if it will work with interfaces, but it will definitely work with abstract classes.
I think you have to annotate the interface too with #Entity and we have to annotate #Transient on all getters and setters of interface.