I'm facing a problem trying to make a JPA repository on an abstract class.
What I'm willing to do is a method that filters, paginates and returnes 3 differents kind of objects in a single list. Some have shared properties (grouped in AbstractClass).
Here are my different classes :
Mother abstract class
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "te_abstract_data")
#DiscriminatorColumn(name="data_type")
public abstract class AbstractData {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "data_type")
#Enumerated(EnumType.STRING)
private DataType dataType;
}
AbstractClass
#MappedSuperclass
public class AbstractClass extends AbstractData {
#ManyToOne
#JoinColumn(name = "fk_obj_id")
private ObjEntity opbj;
}
ClassA & ClassB classes
#Entity
#DiscriminatorValue("CLASS_A")
#Table(name = "te_class_a")
#PrimaryKeyJoinColumn(name="fk_data_id")
public class ClassAEntity extends AbstractClass {
// some fields...
}
ClassC
#Entity
#DiscriminatorValue("CLASS_C")
#Table(name = "te_class_c")
#PrimaryKeyJoinColumn(name="fk_data_id")
public class ClassCEntity extends AbstractData {
// some fields...
}
And here is my repository :
#Repository
public interface DataDao extends JpaRepository<AbstractData, Integer> {
#Query(value =
"SELECT ad " +
"FROM AbstractData ad " +
"WHERE ad.obj.name = :objName " +
// some other filters on various fields
"ORDER BY ad.id ASC"
)
List<AbstractData> findFiltered(
Pageable pageable,
String objName
);
}
The current query in my repository ignores only returns ClassB object, even if ClassA and C's objects are well initialized. I have no idea about what could be wrong...
Any idea how I could solve this ?
Related
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.
I have a persistence model like this one :
#Entity
#Table(name="CMM_DT_EMPLOYEE")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "EMP_TYPE")
public abstract class Employee {
#Id
protected Integer employeeId;
...
}
#Entity
#DiscriminatorValue(value = "FULL")
public class FullTimeEmployee extends Employee {
protected Integer salary;
// ...`enter code here`
}
#Entity
#DiscriminatorValue(value = "PART")
public class PartTimeEmployee extends Employee {
protected Float hourlyWage;
}
Named query (select c from FullTimeEmployee c) not working. Its returning only one row although there are many rows for this discriminator type in the Employee Table. Please help.
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
I'm trying to access a property defined in #MappedSuperclass in a Criteria Query with JPA meta-model (Hibernate 4.2.8):
#MappedSuperclass
public class BaseEntity {
private DateTime createdOn;
}
My Entity:
#Entity
#Table(name = "HISTORY")
public class History extends BaseEntity implements Serializable {
private Long id;
}
How to access createdOn?
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<History> c = cb.createQuery(History.class);
Root<History> h = c.from(History.class);
h.orderBy(cb.asc(a.get(History_.createdOn)));
History_:
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(History.class)
public abstract class History_ extends com.test.BaseEntity_ {
public static volatile SingularAttribute<History, Long> id;
}
Is there a way to access base class' properties?
Of course there is a way. As I see in your code, you already access it: History_.createdOn is a property of the MappedSuperclass. If by "to access" you mean to select, than you simply do:
query.select(History_.createdOn)
I am using Hibernate-search for searching data in my Jboss application. I have 3 JPA entity classes that all extend BaseEntity class and each are indexed by Lucene. For example:
#MappedSuperclass
public abstract class BaseEntity implements Serializable {
#Temporal(TemporalType.TIMESTAMP)
private Date created;
public abstract Long getId();
}
#Entity
#Table(name = "DVD")
public class Dvd extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Field
private String title;
}
#Entity
#Table(name = "BOOK")
public class Book extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Field
private String author;
}
Now I would like to search for either DVD title or Book author by wildcard search query and get the result list as List. This is what I have this far:
public List<BaseEntity> search(String query, int firstResult, int maxResults) {
List<BaseEntity> results = null;
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
Query luceneQuery = new WildcardQuery(new Term("*", "*" + query + "*"));
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(luceneQuery, BaseEntity.class);
fullTextQuery.setFirstResult(firstResult);
fullTextQuery.setMaxResults(maxResults);
results = fullTextQuery.getResultList();
return results;
}
But with this I am not getting any results. How is it possible to get this to work or is there even way without using buildQueryBuilder for each entity? Thanks!
You'll want to use the varargs-style method for the classes, like so:
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(luceneQuery, DVD.class, Book.class);
This is because when Hibernate Search creates the search query, it adds the class name(s) to the query (for the _hibernate_class field, which is the indexed class' name).