Let's say I have a superclass called Vehicle like this:
#Entity
public class Vehicle {
private LocalDateTime dateTimeOfCreation;
}
And, let's say I have a subclass called Car like this:
#Entity
public class Car extends Vehicle{
}
And, I have a I want to select all cars that are created after some date. And, although dateTimeOfCreation field is in superclass, I need to be able to query the subclass for the reason that is not easy for me to explian.
I tried this query: SELECT c from Car c WHERE c.dateTimeOfCreation > :dateTime
However, I get an ORA-00904: Invalid Identifier error, which is in some way logical because the class car doesn't have that field and Cars. Also, I am using a JOINED INHERITANCE, so every class has it's table and dateTimeOfCreation is stored in Vehicle table. That's something I can't change, again for the reason hard to explain.
EDIT: The code I gave is just an example. In reality. The Vehicle is a part of a framework that I shouldn't change, so it already has #Entity annotation.
Car is a class I implemented, that also needs to be an entity. The framework, however, keeps track of times of creation and I need to use that information in a query. However, I can't query Vehicle directly because, I need just the cars, not trucks, bikes etc.
You declare Vehicle as en entity as you have annotated it with javax.persistence.Entity You should not or otherwise you should declare it as an abstract class.
You can also specifying mapped superclasses by annotating the Vehicle class with the javax.persistence.MappedSuperclass annotation.
For example :
#MappedSuperclass
public class Vehicle {
private LocalDateTime dateTimeOfCreation;
}
The solution is suitable if you don't want to query Vehicle entities.
class Vehicle
#Entity(name = "vehicle")
#Inheritance(strategy= InheritanceType.JOINED)
public class Vehicle {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private LocalDateTime dateTimeOfCreation;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public Date getDateTimeOfCreation() {
return date;
}
public void setDateTimeOfCreation(Date date) {
this.date = date;
}
}
Class Car:
#Entity(name = "car")
#PrimaryKeyJoinColumn(name = "vehicle_id")
public class Car extends Vehicle {
}
Dao class:
public class Abc {
-----your logic-----
Session session = HibernateUtil.getSession();
Query query = session.createQuery("from car as c where c.dateTimeOfCreation >= :date");
query.setParameter("date", LocalDateTime.now());
List<RegularEmployee> regularEmployees = query.list();
}
Related
I have read the O/R Mapping of Hibernate and I just can't seem to get past the part on polymorphism.
According to https://docs.jboss.org/hibernate/orm/5.0/manual/en-US/html/ch05.html,
Implicit polymorphisms means that instances of the class will be
returned by a query that names any superclass or implemented interface
or class, and that instances of any subclass of the class will be
returned by a query that names the class itself
whereas
Explicit polymorphisms means that class instances will be returned
only by queries that explicitly name that class. Queries that name the
class will return only instances of subclasses mapped
I just want to understand how these 2 work. Can somebody explain these terms using an example(doesn't have to be too complex) with the use of code? I would appreciate your help
First of all the org.hibernate.annotations.Entity annotation is deprecated now. You should use the #Polymorphism annotation instead.
Now, imagine that you have the following schema:
create table TST_STUDENT
(
st_id int not null,
st_name varchar(200),
primary key (st_id)
);
insert into TST_STUDENT values (1, 'Kostya'), (2, 'Yulia'), (3, 'Borya'), (4, 'Misha');
create table TST_TEACHER
(
tcr_id int not null,
tcr_first_name varchar(200),
tcr_last_name varchar(200),
primary key (tcr_id)
);
insert into TST_TEACHER values (1, 'Mikhail', 'Bulgakov'), (2, 'Leo', 'Tolstoy');
and the following mapping:
public interface Person
{
Long getId();
String getName();
}
#Entity
#Table(name = "TST_STUDENT")
public class Student implements Person
{
#Id
#Column(name = "st_id")
private Long id;
#Column(name = "st_name")
private String name;
public Student()
{
}
// getters / setters
}
and Teacher entity:
import org.hibernate.annotations.Polymorphism;
import org.hibernate.annotations.PolymorphismType;
#Entity
#Table(name = "TST_TEACHER")
// #Polymorphism(type = PolymorphismType.EXPLICIT)
public class Teacher implements Person
{
#Id
#Column(name = "tcr_id")
private Long id;
#Column(name = "tcr_first_name")
private String name;
#Column(name = "tcr_last_name")
private String lastName;
public Teacher()
{
}
// getters / setters
}
Now, if you run the following query:
List<Person> persons = em.createQuery("select p from com.your.entities.Person p", Person.class).getResultList();
you will get all rows from the TST_STUDENT table plus all rows from the TST_TEACHER table.
But, if you uncomment this line:
#Entity
#Table(name = "TST_TEACHER")
#Polymorphism(type = PolymorphismType.EXPLICIT) // now we use explicit polymorphism for the Teacher entity
public class Teacher implements Person
The mentioned above query will return only rows from the TST_STUDENT table.
This is what this annotation mean.
By default, when you query a base class entity, the polymorphic query will fetch all subclasses belonging to the base type. You can even query interfaces or base classes that don’t belong to the JPA entity inheritance model.
P.S. See also this part of documentation.
I know there are several questions on this argument, but I think mine is a bit different.
I'm trying to use JPA notation instead of XML mapping. In my queries always there's an undesired dtype column, and I don't want to use neither discriminator column and formula.
I have four classes as follow:
The first named ObjectUUID. All classes extend this super class.
This class is used only to define id field, as follow:
#MappedSuperclass
public class ObjectUUID {
#Id
#GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
protected String id;
// getter and setter and other static methods
}
Then I have another class, named TrackSys where I define other fields (as insert date and update date) as follow:
#MappedSuperclass
public class TrackSys extends ObjectUUID{
#Column(name="dt_ins")
private CustomCalendar dtInsert;
#Column(name="dt_upd")
private CustomCalendar dtUpdate;
// getter and setter
}
the third and the forth classes are beans mapped on DB, as follow:
#Entity
#Table(name="patient")
public class PatientUUID extends TrackSys {
}
#Entity
#Table(name="patient")
public class Patient extends PatientUUID {
#Column(name="surname")
private String surname;
#Column(name="name")
private String name;
#Column(name="cf")
private String cf;
// getter and setter
}
I define a repository to query my patient table, as follow:
public interface PatientRepository extends JpaRepository<Patient, Long> {
List<Patient> findBySurname(String surname);
}
When my Patient query runs, the generated SQL is the follow:
select patient0_.id as id2_2_, patient0_.dt_ins as dt_ins3_2_,
patient0_.dt_upd as dt_upd4_2_, patient0_.cf as cf7_2_,
patient0_.surname as surname8_2_, patient0_.name as name11_2_,
from patient patient0_ where patient0_.dtype='Patient'
and patient0_.surname=?
Now...
I don't want dtype column and I don't want to use discriminator formula.
With the XML mapping this is possible without particular properties to specify.
With JPA annotation I try in order:
Use #Inheritance(strategy = InheritanceType.SINGLE_TABLE) but dtype is always present
Use #Inheritance(strategy = InheritanceType.JOINED) but dtype is always present
Now, my feeling versus dtype is only hate, how can I get this simple query, as follow:
select patient0_.id as id2_2_, patient0_.dt_ins as dt_ins3_2_,
patient0_.dt_upd as dt_upd4_2_, patient0_.cf as cf7_2_,
patient0_.surname as surname8_2_, patient0_.name as name11_2_,
from patient patient0_ where patient0_.surname=?
I have an existing table without discriminator column and I need to map it with single table hierarchy, how to map this?
here is my table
vehicle
========
vehicle_id
manufacturer
load_capacity
passenger_capacity
I have 3 classes
Vehicle.java
vehicleId;
manufacturer;
TransportationVehicle.java
loadCapacity;
PassengerVehicle.java
passengerCapacity;
If you have no discriminator, then you need another condition to distinguish TransportationVehicle and PassengerVehicle. I guess in your case you could use:
TransportationVehicle: loadCapacity IS NOT NULL
PassengerVehicle: passengerCapacity IS NOT NULL
As JPA inheritance always needs a discriminator, you will have to use #MappedSuperclass and two #Entity classes with a corresponding #Where annotation:
#MappedSuperclass
public abstract class Vehicle {
#Id
private Long vehicleId;
private String manufacturer;
}
#Entity #Where(clause = "loadCapacity IS NOT NULL")
public class TransportationVehicle extends Vehicle {
private int loadCapacity;
}
#Entity #Where(clause = "passengerCapacity IS NOT NULL")
public class PassengerVehicle extends Vehicle {
private int passengerCapacity;
}
Major disadvantage of this approach compared with real JPA inheritance: You can't reference the mapped superclass in JPA - neither in queries (SELECT v FROM Vehicle v) nor in another entity (#OneToOne Vehicle vehicle).
One way to do it is use #MappedSuperclass on the Vehicle class and then map TransportationVehicle and PassengerVehicle to the same table.
This way you will inherit the mapped fields from Vehicle without having to map it as an entity.
I have two entity-classes A and B. For A there is only one instance of class B. Through a lifecicle of application I need to create new instnace of B for A. But for history log I need to store previous instance of B with links to an this A instance. So I created next mapping:
#Entity
class A {
#OneToOne
#JoinColumn(name="B_ID")
B b;
}
#Entity
class B {
#OneToOne
#JoinColumn(name="A_ID")
A a;
}
///////
CREATE TABLE A_TABLE (ID uuid, B_ID uuid, FOREIGN KEY (B_ID) REFERENCES B_TABLE(ID));
CREATE TABLE B_TABLE (ID uuid, A_ID uuid, FOREIGN KEY (A_ID) REFERENCES A_TABLE(ID));
I already have some correct data in my tables, but each time, when I trying to get any instance of A class, the b field is null. So, what am I doing wrong?
UPD_0
Ok, here what I'm realy dealing with:
#MappedSuperclass
public abstract class BaseUuidEntity {
#Id
#Column(name = "ID")
#Persistent
protected UUID id;
}
#MappedSuperclass
public class StandartEntity extends BaseUuidEntity { ... }
#MappedSuperclass
public abstract class AbstractEntity extends BaseUuidEntity { ... }
#Entity(name = "CardEntity")
#Table(name = "TBL_CARD")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "CARD_TYPE", discriminatorType = DiscriminatorType.INTEGER)
#DiscriminatorValue("0")
public class CardEntity extends AbstractEntity { ... }
#Entity("aEntity")
#DiscriminatorValue("1")
#Table(name = "A_TABLE")
class A extends CardEntity {
#OneToOne
#JoinColumn(name="B_ID")
B b;
public String getBName() {
return b.getName(); // NullPointerException
}
}
#Entity("bEntity")
#Table(name = "B_TABLE")
class B extends StandartEntity {
#Column(name="name")
String name;
public String getName() {
return this.name;
}
}
-- A_TABLE (ID, B_ID)
'41a2647d-2ef6-f507-92ee-bff0f784b6f3', '5d3c66da-b377-11e4-bc9c-1008b124eacf'
-- B_TABLE (ID, A_TABLE, NAME)
'5d3c66da-b377-11e4-bc9c-1008b124eacf', '41a2647d-2ef6-f507-92ee-bff0f784b6f3', 'Some text'
I'm getting all A entities (in my case - it's one)
select e from aEntity e
and trying to get name of b entity in each of them, but getting nullpointer, cause b is null;
I'm not sure if it will make any difference, but try changing the code in getBName() to use the getter instead of directly referencing the instance variable b:
public String getBName() {
return getB().getName();
}
instead of:
public String getBName() {
return b.getName(); // NullPointerException
}
I suspect that this could be the issue because JPA implementations create proxies for entities, which are usually subclasses of your entities, and these proxies override your getters and setters. So if you don't use the getter it could be that the instance variable does not get initialized properly.
you need mappedBy anotation: http://en.wikibooks.org/wiki/Java_Persistence/OneToOne
to inform java who is in charge of this relationship and when the 'foreign'id' is storred. You also need the foreign key in only one of the entities not both!
The title is a bit weird, so let me clarify.
I have two objects, Garage and Vehicle, in a one-to-many relationship. There are multiple types of vehicles, such as car and truck; the type is persisted as a string in the Vehicle table.
Here's the two classes:
#Entity
#Table(...)
public class Garage {
....
#Column(name = "garageId")
private Integer garageId;
#OneToMany
#JoinColumn(name = "garageId")
private Set<Vehicle> vehicles;
....
}
#Entity
#Table(...)
public class Vehicle {
....
#Column(name = "garageId")
private Integer garageId;
//could be "Truck" or "Car"
#Column(name = "type")
private String type;
....
}
In order to differentiate between types of Vehicles, currently we have to look at the type column and use an enum. What I'd like to do is have subclasses of Vehicle, such are Car and Truck, to represent the different types rather than relying on the Type field. Then my code can instanceof to determine the type instead of using that field.
However, I don't know how to tell Hibernate how to instantiate subclasses based on the value of the Type column, or if it even can.
I'd appreciate any help you guys can give. Thanks in advance!
If you want to save the current database schema, you need to use SINGLE_TABLE inheritence strategy with type column as a discriminator:
#Entity
#Table(...)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "type")
public abstract class Vehicle { ... }
#Entity
#DiscriminatorValue("...")
public class Car extends Vehicle { ... }
#Entity
#DiscriminatorValue("...")
public class Truck extends Vehicle { ... }