We have following hierarchy in our application:
#MappedSuperclass
public abstract class AbstractDemandOrMeasureBE {
}
#Entity
#Inheritance
#DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.INTEGER)
#Table(name = "V_VIEW2")
public abstract class AbstractDemandOrConcreteMeasureBE extends AbstractDemandOrMeasureBE {
#Column(name = "VC_ID")
private Long vcId;
}
#Entity
#DiscriminatorValue("2")
public class MinimalDemandBE extends AbstractDemandOrConcreteMeasureBE {
..
}
#Entity
#DiscriminatorValue("1")
#HasRelationsAnnotatedAsLazyLoaded
public class ValidationMeasureBE extends AbstractDemandOrConcreteMeasureBE {
..
}
In other object I am trying to load those entities like that:
#Table(name = "V_VIEW2")
public class VCBE extends SomeVeryAbstractBE {
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "VC_ID")
private List<ValidationMeasureBE> validationMeasures;
public transient static final String ATTRIBUTE_VALIDATION_MEASURES = "validationMeasures";
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "VC_ID")
private List<MinimalDemandBE> minimalDemands;
public transient static final String ATTRIBUTE_MINIMAL_DEMANDS = "minimalDemands";
There is a precompiled query to load all hierarchy, which load some other parent objects. There is also a hint for the query - eclipselink.left-join-fetch=PP.VCBE.validationMeasures (if this is changed to eclipselink.left-join-fetch=PP.VCBE.minimalDemands, then minimal demands are loaded, but validation measures (entries with discriminator 1) are also loaded into the minimal demands collection - but those should not be loaded).
Now, when query is executed validationMeasures collection if filled with objects, but all those object are actually minimal demands and have 2 as a discriminator value in the database.
The query, which gets executed is following:
SELECT * FROM V_VIEW1 t1
LEFT OUTER JOIN V_VIEW0 t0 ON (t0.PP_D = t1.ID)
LEFT OUTER JOIN V_VIEW2 t2 ON (t2.VC_ID = t0.ID)
WHERE (((t1.ID = ?) AND (t1.HP_ID = ?))
AND t1.HP_IS IN (SELECT t3.ID FROM V_VIEW t3 WHERE (t3.HWPG_ID = ?)))
bind => [3 parameters bound]
As I can see there is no DISCRIMINATOR constraint in the query, why?
Any ideas of such a behavior? And how can I tell eclipselink to load collection, depending on discriminator value?
Can you include the JPQL query and hints you use to get this SQL.
So, you are saying it works when you use a join-fetch, but not a left-join-fetch?
This seems like it may be a bug, that the inheritance discriminator expression is not being included when using an outer join. If this is the case, please log a bug for this and vote for it.
Your model is very odd though. Why split the two subclasses into two separate relationships? Having one would be much more efficient. Or if you do split them, you should be using different foreign keys, not the same one. Sharing the same foreign key for two different relationships is probably not a good idea.
Related
I was trying to optimise number of calls for my schema creational endpoint and get rid of n+1 problem. And I actually did it replacing them with only 2 calls. I have achieved it with Named Queries but I wonder if it is possible to do it with nativeQuery=true.
So, here is the situation:
Class A:
#Entity
#IdClass(AId.class)
#Table(name ="A")
#Data
class A implements Serializable{
#Id
#Column(name = "ID")
private Integer id;
// code omitted...
#ManyToOne(fetch=FetchType.Lazy)
#JoinColumns(
...
)
private B b;
}
Class B:
#Entity
#IdClass(AId.class)
#Table(name ="B")
#Data
class B implements Serializable{
#Id
#Column(name = "ID")
private Integer id;
// code omitted...
#OneToMany(mappedBy="b", cascade=Cascade.ALL, fetch=FetchType.Lazy)
#JoinColumns(
...
)
private List<A> aList;
}
The problem occurs when I try to fetch the data with generated or native queries.
It grabs B entities when I fetch A though it's Lazy for A.
Expected behaviour is the executing a query as follows:
Hibernate:
/* dynamic native SQL query */ SELECT
*
FROM
A a
WHERE
a.ID IN (
?
)
But right after this (no matter how I played with dynamic native query) I have one more query for B entity that I don't need:
Hibernate:
/* load com.example.to.B */ select
b0_.id as id1_1_0_,
from
B b0_
where
b0_.id=?
Why is this so and is there any way to avoid it?
Thanks in advance.
Set a breakpoint in e.g. org.hibernate.resource.jdbc.internal.EmptyStatementInspector#inspect to see which code triggers the lazy initialization. Maybe it's your debugging that triggers this through a toString implementation.
Hibernate cannot fetch lazily for ToOne relationships.
The field b can be null in A, and hibernate has to check with the table b before confirming to populate the field with null. The query for B you observed is the result.
You may consider using #MapsId, e.g.:
#ManyToOne
#MapsId(“id”)
private B b;
You may read further about #MapsId here:
https://www.objectdb.com/api/java/jpa/MapsId
Group by entities is possible in HQL, but it seems that by entities mapped with joined inheritance doesn't.
select a, count(r) from Root r join r.a a group by a
Executing the above query results in a sql with insufficient columns in group by:
select
suba1_.id as col_0_0_,
count(root0_.id) as col_1_0_,
suba1_.id as id1_12_,
suba1_1_.super_data as super_da2_12_,
suba1_.sub_data as sub_data1_10_
from root root0_
inner join suba suba1_ on root0_.a_id=suba1_.id
inner join supera suba1_1_ on suba1_.id=suba1_1_.id
group by suba1_.id
Which gives the following error message:
o.h.engine.jdbc.spi.SqlExceptionHelper: expression not in aggregate or GROUP BY columns: SUPERA1_.SUPER_DATA in statement
The entities are described as followed:
#Entity
public class Root {
private #Id Integer id;
#ManyToOne
private SubA a;
}
#Entity
public class SubA extends SuperA {
private String subData;
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class SuperA {
private #Id Long id;
private String superData;
}
Also if changed the type of Root::a to SuperA, the sql generated by the hql will have the same problem.
So is group by entities with joined inheritance type possible or am I missing something?
PS. This hql query does work in case if SuperA is mapped with table per class inheritance type but then fails with the same problem if type of Root::a is changed to SuperA as well.
Hibernate version: org.hibernate:hibernate-core:jar:5.4.32.Final:compile
Yes, with a bit of trickery, to anwser my own question. The missing column for the group by in the sql is the column id of SuperA, so the solution would be to include it. I found that possible by mapping the superclass's id with an extra column and reference it in the group by along side the entity.
So, in SuperA an extra column mapping superId would be added:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class SuperA {
private #Id Long id;
#Column(name="id", updatable = false, insertable = false)
private Long superId;
private String superData;
}
And referenced in the group by
select a, count(r) from Root r join r.a a group by a, a.superId
This solution was tested only for HSQLDB and PostgreSQL.
I have the following classes:
#Entity
public class EventOrderLine {
#EmbeddedId private EventOrderLineId id;
}
#Embeddable
public class EventOrderLineId implements Serializable {
#ManyToOne
#JoinColumn(name = "eventid")
#JsonIgnore
private Event event;
#ManyToOne
#JoinColumn(name = "orderlineid")
#JsonIgnore
private OrderLine orderLine;
}
#Entity
public class OrderLine {
#OneToMany
#JoinColumn(name = "orderlineid")
#JsonIgnore
private List<EventOrderLine> eventOrderLines = new ArrayList<>()
}
Basically I'm trying to join the two tables via the Criteria API but having issues since this is what I want to do:
Root eventOrderLine = criteriaQuery.from(EventOrderLine.class);
Join orderLine = eventOrderLine.join("orderLine");
Of course this give me this issue since the mapping isn't directly on the entities themselves:
Unable to locate Attribute with the the given name [orderLine] on this ManagedType [com.EventOrderLine]
I've been trying to tweak the join to drill into the embeddedId but not sure if I need to go a step further and modify how my entities are mapped. I feel like it's probably something simple I'm missing but having trouble finding this specific question.
The event field is a member of EventOrderLineId and not EventOrderLine. In your criteria query, you first need to navigate to id. The catch is that Root.path("id") returns an instance of Path, which does not allow further joins.
The trick is to use a 'fake' join with the id field like so: eventOrderLine.join("id").join("event")
eventOrderLine.get("id").get("event") would likely work just as well, but it wouldn't allow you to specify the join type.
first try to get the property id of EventOrderLine entity and then join. So, it would be -
Root eventOrderLine = criteriaQuery.from(EventOrderLine.class);
Join orderLine = eventOrderLine.get("id").join("orderLine")
JBoss EAP 6
Hibernate 4
I have a J2EE application with a web browser client. ( Apache click )
Both the internal business logic and the client use the same entity objects.
I would like to have all relations in the entities set to lazy loading. This way I have good performance.
But when using the entities in the client ( that is the server side code of apache click ) I would need a lot of the relations to be eager loaded. The client code is accessing the back-end through a session bean.
So I have a couple of ways I can solve this:
Create 2 of each JPA entities, one with eager loading and one with lazy loading. And then use the one with eager loading in the client, and the one with lazy loading in the server. Most of the server logic will be in a transaction, so lazy loading is fine here.
Make all relations lazy loading. When accessing the entities from the client, make sure there is a transaction. ( #TransactionAttribute(TransactionAttributeType.REQUIRED) )
and code the access to the necessary fields so they are accessible after session bean call.
But that means that I have to start a transaction when that is not required, i.e. if I am only getting some objects. And I have to maintain more code. And I have to know exactly what relations the client needs.
Create an inheritance hierarchy, where I have a super entity, and then 2 child, one with objects relations lazy loaded, and one with only values, no objects. i.e. :
Super
#MappedSuperclass
public class SuperOrder {
#Id
#Column(name = "id")
#GeneratedValue(.....)
private Long id;
#Column(name = "invoice", length = 100)
private String invoice;
Child 1
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "testorder")
#SequenceGenerator(....)
public class Order extends SuperOrder {
#ManyToOne(targetEntity = PrintCustomerEnt.class, fetch = FetchType.EAGER, optional = true)
#JoinColumn(name = "print_customer_id", nullable = true)
#ForeignKey(name = "fk_print_customer")
#Valid
private PrintCustomerEnt printCustomer;
public PrintCustomerEnt getPrintCustomer() {
return printCustomer;
}
public void setPrintCustomer(final PrintCustomerEnt printCustomer) {
this.printCustomer = printCustomer;
}
}
Child 2
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "testorder")
#SequenceGenerator(...)
public class LazyOrder extends SuperOrder {
#Transient
private String printCustomerName;
#Column(name = "print_customer_id", nullable = true)
private Long printCustomerId;
What is the best practice... or is there something other good way to do this.
Basically the problem is I want to use the same entities in different scenarios. Sometimes I need eager loading, and sometimes I need lazy loading.
I suggest that you create just one JPA entity with lazy relationships, and when you need to load eagerly some of them create a Service that uses JPQL(HQL) to do some FETCH trick. The idea is one JPA entity and many services.
I've been programing in JPA 2 for some a while now, and I can say there are couple of now written rules that I almost always apply:
Use LAZY Inicialization on all your OneToMany, ManyToMany Relations
Use EAGER Inicalization on all your OneToOne, ManyToOne Relations
This rules apply on 99% of my projects. I think these are best practices due to my personal experience and some research I've been doing.
Note: I must say I do not use JOIN FETCH on Lazy Inicialization, instead I write a Prefetch Method. Example:
#Entity
class Entity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
private Integer id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "mappedName",
orphanRemoval = true)
private List<Child1> collection1;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "mappedName",
orphanRemoval = true)
private List<Child2> collection2; }
And then we have the Controller:
class EntityController{
public Entity findCompraFolioFull(Integer id) {
EntityManager em = getEntityManager();
try {
Entity entity = em.find(Entity.class, id);
//Initialize Collections inside Transaccion, this prevents
//LazyInizialization No Proxy Exception later in code when calling
//hollow collections
cp.getCollection().size();
cp.getCollection().size();
return cp;
} finally {
em.close();
}
}
}
I don't recomend FETCH JOIN
public Entity findEntityByJoinFetch(Integer id) {
EntityManager em = getEntityManager();
try {
TypedQuery<Entity> tq = em.createQuery(
"SELECT e FROM Entity e\n"
+ "LEFT JOIN FETCH e.collection1\n"
+ "LEFT JOIN FETCH e.collection2\n"
+ "WHERE e.id = :id", Entity.class);
tq.setParameter("id", id);
return tq.getSingleResult();
} finally {
em.close();
}
}
Reasons I don't recomend Fetch Join Appoach:
If your collections are java.util.List type then this getSingleResult() will fail in hibernate due to lack of capacity to fetch MultipleBags without indexing notations on your OneToMany Relation.
You can always change the type of your collections to java.util.set in order to multiple bags to be fetched but this brings new kind of situations to deal with, Sets aren't ordered and HashCode() method won't work correctly so you'll have to #Override it inside Children Classes, and if you are using JAVAFX TableView to bind model to Items you won't be able to bind collections Set Type to Item Property of TableView, not directly at least.
I want to create Many-One Mapping between two tabels, Expense(ID, NAME, CATEGORY) and
Category(ID, NAME).
In my class i have created a field 'Category category' and its setters and getters.
I did them after seeing some stuff from internet. What are all the changes i have to do in my Category.java class. For now, its looks like,
public class Category{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int catId;
private String catName;
public Category() {
}
public int getCatId() {
return this.catId;
}
public void setCatId(int catId) {
this.catId = catId;
}
public String getCatName() {
return this.catName;
}
public void setCatName(String catName) {
this.catName = catName;
}
}
I dont want to do mappings with xml config. I think, annotations is good for a beginner like me.
And my Old! SQL query looks like,
SELECT EXPENSES.EXPNS_ID, EXPENSES.CAT_ID, EXPENSES.NAME, CATEGORY.CAT_NAME FROM EXPENSES INNER JOIN CATEGORY ON EXPENSES.CAT_ID = CATEGORY.CAT_ID WHERE USER_NAME="+currentUserName
How to use inner join in Hibernate?
Any Suggestions!!
Thanks!
Update
Thanks for all answerers,
I tried what you told and it returns a empty list.
To, test i set the 'userName=Tamil' which is in the table.
The query generated by Hibernate is looks like below,
select expens0_.expnsId as expnsId1_, expens0_.catId as catId1_, expens0_.category_catId as category7_1_, expens0_.userName as userName1_ from Expens expens0_ inner join Category category1_ on expens0_.category_catId=category1_.catId where expens0_.userName=?
As a beginner, i have some doubts in JPQL, I want catName from Category[catId, catName] table. And the catId is also available in Expens[expnsId, catId, userName].
By adding the below lines in Expens.java class, how it will give me catName along with the other variables in the Expens table.
#ManyToOne
private Category category
// getters, setters
I cant able to understand it. Without understanding this i cant move further, i have to give more mappings in my project. If clear with this mapping, i can move to the rest with confidence.
The query i used is pascal's version: Query query = hSession.createQuery("SELECT e FROM Expens e JOIN e.category c WHERE e.userName = :userName").setParameter("userName", userName);
For me, the query generated by hibernate is looks like same as my Old SQl query. I cant able to find problem here.
Actually, a big part of the documentation that would be useful in your case is located in the Hibernate Annotations Reference Guides (links provided below). Reading it would be very worth it.
That being said, regarding your specific question, the simplest possible mapping would be:
#Entity
public class Expense {
#Id #GeneratedValue
private Long;
#ManyToOne
private Category category
// getters, setters
...
}
That's all.
If you want to make it bi-directional, you'll have to add a OneToMany on the other side (and don't forget the mappedBy element since the association is bidirectional):
#Entity
public class Category {
#Id #GeneratedValue
private Long id;
#OneToMany(mappedBy="category")
private Set<Expense> expenses = new HashSet<Expense>();
....
}
And a possible JPQL query would be:
SELECT e FROM Expense e JOIN e.category c WHERE e.username = :username
Update: Hibernate and JDBC are different. With Hibernate, you need to think objects and the above HQL query (which was more an example) will actually return a List<Expense>. To get a category name, iterate over the results and navigate through the association. For example:
List<Expense> expenses = ... // some code to retrieve a list by username
for (Expense expense : expenses) {
System.out.println(expense.getCategory().getName());
}
References
2.2. Mapping with JPA (Java Persistence Annotations)
2.2.5.2. Many-to-one
As Bozho suggested,
#ManyToOne(fetch=FetchType.EAGER) // Gonna be eager by default anyway
#JoinColumn(name="CATEGORY_ID")
private Category category;
Plus this in your Category class to make it bidirectional,
#OneToMany(mappedBy="category")
private List<Expense> expense;
You need not do an inner join like that. When you query the expense, the related category will automatically get loaded eagerly, most likely using join.
In your Expense class have:
#ManyToOne
#JoinColumn(name="CATEGORY_ID")
private Category category
As pointed in the comments, if you need to access all expenses in a given category, i.e. have the one-to-many relationship, you can have:
#OneToMany
private List<Expense> expenses;
I, for example, prefer to use as little #OneToMany mappings as possible - you'd have to manager eager/lazy loading, at some point limiting the number of results, etc. For them I tend to use HQL queries that fetch the subset of objects (expenses in your case) that I need.