Having abstract data type for attribute in JPA - postgresql

I have following entities -:
#MappedSuperclass
abstract class Enterprise {
}
Two classes implementing Enterprise
#Entity
class Vendor() : Enterprise {
#OneToMany
#JoinColumn(name="contactPerson_id")
lateinit var contactPerson: List<ContactPerson>
}
#Entity
class Customer() : Enterprise {
#OneToMany
#JoinColumn(name="contactPerson_id")
lateinit var contactPerson: List<ContactPerson>
}
And for ContactPerson Class we have reference for each type of Enterprise
#Entity
#Table(name = "CONTACT")
class ContactPerson {
#JoinColumn(name = "vendor_id")
#ManyToOne
var vendor: Vendor
#JoinColumn(name = "vendor_id")
#ManyToOne
var customer: Customer
#Id
val id: Int? = null
}
But instead of keeping two reference i want to have one reference of abstract type Enterprise something like this
#Entity
#Table(name = "CONTACT")
class ContactPerson {
#JoinColumn(name = "vendor_id")
#ManyToOne
var enterprise: Enterprise
#Id
val id: Int? = null
}
But this give me error "Many To One' attribute type should not be 'Mapped Superclass"
which i understand is due to the fact that Enterprise is not an Entity
and will not be mapped to a table which is exactly what i want .
How can i achieve this without having an Entity superclass

Related

JPA entity inheritance: which instance to create for lazy initialization?

JPA entity inheritance: which instance to create for lazy initialization? For example,
Single table mapping strategy:
Teacher(abstract)
/ \
FullTimeTeacher PartTimeTeacher
Entity School referencing Teacher:
#Entity
public class School {
#ManyToOne(fetch=FetchType.LAZY)
private Teacher manager;
}
When retrieving a School entity from database, the school's manager is lazy, not initialized. Which type of proxy will be instantiated? Teacher is abstract.
The proxy may not match the actual referenced type (Full Time or Part Time Teacher).
I was curious myself, and tested it with the following setup:
#Entity
public class Garage {
#Id
#GeneratedValue
private Long id;
#OneToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
private Car car;
...
}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
...
}
#Entity
public class SportsCar extends Car {
private int hp;
...
#Override
public String toString() {
return "SportsCar [hp=" + hp + ", getId()=" + getId() + "]";
}
}
The test:
Garage garage = new Garage();
SportsCar car = new SportsCar();
car.setHp(350);
garage.setCar(car);
em.persist(garage);
...
Garage garage = em.find(Garage.class, garage.getId());
System.out.println(garage.getCar().getClass());
System.out.println(garage.getCar());
System.out.println(garage.getCar() instanceof SportsCar);
The above prints:
class com.example.Car_$$_jvstd71_f
SportsCar [hp=350, getId()=1]
false
Conclusion: Hibernate will create a proxy of the superclass. That proxy will, however, delegate method calls to the subclass instance.

JPA Criteria to query hierarchy of child objects

I have two tables that are represented by following entity object hierarchies:
#Entity
#Table(name = Transport.TABLE_NAME)
#DiscriminatorColumn(name="transport_type", discriminatorType = DiscriminatorType.INTEGER)
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Transport {
...
private Date departure;
}
#Entity
#DiscriminatorValue("1")
public class Bicycle extends Transport {
...
#OneToOne(mappedBy = "transport", fetch = FetchType.LAZY)
private BikePassenger passenger;
}
#Entity
#DiscriminatorValue("2")
public class Car extends Transport {
...
#OneToMany(mappedBy = "transport", fetch = FetchType.EAGER)
private List<CarPassanger> passengers;
}
#Entity
#Table(name = Passenger.TABLE_NAME)
#DiscriminatorColumn(name="passenger_type", discriminatorType = DiscriminatorType.INTEGER)
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Passenger {
...
private int passengerGUID;
}
#Entity
#DiscriminatorValue("1")
public class BicyclePassenger extends Passenger {
...
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "transportid")
private Bicycle transport;
}
#Entity
#DiscriminatorValue("2")
public class CarPassenger extends Passenger {
...
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "transportid")
private Car transport;
}
Now using JPA Criteria API (or at least JPA) how do I:
Get all transports that have passengers with specific passengerGUID?
Group transports (along with passengers) by departure date?
As I see it #1 should have nice solution but I was able to get out only with 2 subselects for each subtype. Which looks ugly to me.
And finally third question - is it good model at all? From OOP point of view to me it looks ok, but from ORM point of view and easiness of queries it looks not so good...
p.s. I'm using hibernate JPA 2.1

How to map one to many JPA relationship?

I'm getting Unknown column 'imageprope1_.enid' in 'field list' with the following mapping:
#OneToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name="enid", referencedColumnName="pnid")
private List<EntityImageProperty> imageProperties = new ArrayList<>();
Here's the key entity mapping:
BaseEntityProperty
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="enpptpcd", discriminatorType=DiscriminatorType.STRING)
#Table(name=BaseEntityProperty.TABLE_NAME)
public abstract class BaseEntityProperty implements Serializable {
#Id
#Column(name="enppid")
private String entityPropertyId=null;
#Column(name="enid")
private String entityId=null;
EntityImageProperty
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorValue(EntityImageProperty.DISCRIMINATOR_VALUE)
#Table(name=EntityImageProperty.TABLE_NAME)
#PrimaryKeyJoinColumn(name="enppid")
public class EntityImageProperty extends BaseEntityProperty {
It looks like #JoinColumn(name="enid", referencedColumnName="pnid") tells Hibernate to join on EntityImageProperty.enid, whereas it should join on BaseEntityProperty.enid.

Table per concrete class with Hibernate OGM and mongodb

I'm using mongodb to store json documents, and since I'm using Hibernate ORM for my relational models I've decided to use the OGM for the mongo ones.
Currently all of my OGM entities share the same parent class, it looks something like:
#Entity
public abstract class Document {
private static final Gson GSON = new Gson();
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Type(type = "objectid")
protected String id;
public String id() {
return this.id;
}
#Override
public String toString() {
return Document.GSON.toJson(this);
}
}
#Entity
public class Address extends Document {
private String city;
private String street;
private int house;
}
#Entity
public class Person extends Document {
private String name;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Address> addresses;
}
(simplified of course)
What I expected that would happen when I persist a Person instance is that two collections will be created in the db, one for Person and the other for Address, which I inferred:
The various inheritance strategies are not supported by Hibernate OGM,
only the table per concrete class strategy is used
(Supported entity mapping - Hibernate OGM documentation)
But what happens in reality is that only one collection is created with the name Document with two documents in it:
{
_id : id1,
DTYPE : Person,
name : name of person
}
{
_id : id2,
DTYPE : Address,
city : City of address,
street : Street of address
house : 3
}
What am I missing?
Thanks
I think, it should be:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Document {
...
}

using #Embedabble with a foreign key and manyToMany relation

I wrote an example for the code i am trying to implement, i get an error with Constraint "Student_Teacher_FK" already exists.
the #embiddable class has a foreign key that is created twice with current code.
#Entity
public class Teacher {
#Id
#GeneratedValue
private Long id;
#Column(name = "Name")
private String name;
}
#Entity
public class Student{
#Id
#GeneratedValue
private Long id;
#Column(name = "Name")
private String name;
}
#Embeddable
public class StudentList implements Serializable {
#ManyToMany
#JoinTable(name = "Student_Teacher",
joinColumns =
#JoinColumn(name = "Student_ID", referencedColumnName = "ID"),
inverseJoinColumns =
#JoinColumn(name = "Teacher_ID", referencedColumnName = "ID")
)
#ForeignKey(name = "Student_Teacher_FK", inverseName = "Teacher_Student_FK")
public List<Student> studentList = new ArrayList<Student>();
}
#Entity
public class HistoryTeacher extends Teacher {
#Embedded
#NotNull
private StudentList StudentList = new StudentList ();
}
#Entity
public class LangTeacher extends Teacher {
#Embedded
#NotNull
private StudentList StudentList = new StudentList ();
}
#Entity
public class RetiredTeacher extends Teacher {
// has no students
}
#embeddable : Defines a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity (http://docs.oracle.com/javaee/6/api/javax/persistence/Embeddable.html)
As you are declaring it in 2 different entity, jpa will create associated association table (student-teacher) 2 times with associated fk, which is explicitely named, and so created 2 times too with the same name. Here is your error.
I don't think using #embeddable is appropriated for what you're intending to do. A student has is own existence and is not part of teacher itself (not an uml composition / black diamond) so it's not an embeddable entity. Student list should be held by teacher entity using a simple manyToMany association.