Retrieve Collection of Subclasses Based on Column Value - java

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 { ... }

Related

How to override attribute from embedded column is superclass

I'm trying to override a property of an embedded column existing in the superclass of an entity.
My entities look like this:
#Embeddable
public class Key {
#Column
private String a,
#Column
private String b
}
#MappedSuperclass
public abstract class Superclass {
#EmbeddedId
private Key key;
}
#Entity
#Table(name = "my_entity")
#AttributeOverride(name = "b", column = #Column(name="renamed_b"))
public class MyEntity extends Superclass {
}
I have tried using AttributeOverride on MyEntity, but it doesn't do anything.
It would work if I would move the AttributeOverride annotation on the embedded field, but I cannot modify the superclass.
Is there any solution?
Look, read documentation carefully:
To override mappings at multiple levels of embedding, a dot (".")
notation form must be used in the name element to indicate an
attribute within an embedded attribute.
The name "b" is incorrect.
You should use "key.b"
#Entity
#Table(name = "my_entity")
#AttributeOverride(name = "key.b", column = #Column(name="renamed_b"))
public class MyEntity extends Superclass
}

Get superclass field value using JQPL query in JPA

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();
}

Single table per class hierarchy without discriminator column

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.

Mapping 1 table to multiple classes in JPA

I want to achieve something like this:
#Entity
#Table(name = "beer")
public class Beer {
#Id Long id;
String brand;
String name;
}
#Entity
public class BeerWithIngredients extends Beer {
#OneToMany(mappedBy="beer")
List<BeerIngredient> ingredients;
}
#Entity
public class BeerIngredient {
#Id Long id;
// .. whatever fields
#ManyToOne
#JoinColumn(name = "beer_id")
BeerWithIngredient beer;
}
Physically, all beer data is in one table, but I want to split it into more entities.
Please note that:
I would not like to use discriminator column in the database
There isn't a column that I could use for #DiscriminatorFormula
I do not want to embed Beer inside BeerWithIngredients, because it essentially is not a composition, but proper inheritance
Is there a way of achieving this with JPA (Hibernate)? Right now it complains about missing discriminator column, that I don't plan to provide.
Introduce a new super class RootBeer with all common beer properties. Annotate this class with MappedSuperClass. Make Beer and BeerWithIngredients inherit from RootBeer and annotate them with Entity as well as Table(name="beer").
For an example check this.

About hibernate inheritace mapping and Discriminator column, how do I know which type of object?

In jpa2 inheritance mapping, single table strategy, the discriminator column don't show in enitity object, and implicity mapping with DiscriminatorColumn annotation.
then How do I know which sub object I get?
I expect this:
if(object.obj_type==1){ }
and also, how do I get discriminator value in runtime ?
What you want is to have an abstract super class where you define the discriminator column and the sub classes to define the discriminator value.
#Entity
#DiscriminatorColumn(name = "_type")
public abstract class AbstractSuperClass {
#Column(name = "_type", insertable=false, updatable=false, nullable = false)
private String type;
}
#Entity
#DiscriminatorValue(SubClass.TYPE)
public class SomeSubClass extends AbstractSuperClass {
public static final String TYPE = "SOME_SUBTYPE";
}
So basically at runtime you could just check with instanceof
if(object instanceof SomeSubClass){}
Or even with the type value
AbstractSuperClass object = ..
if(object.getType() == SomeSubClass.TYPE){}

Categories

Resources