EntityNotFoundException LEFT JOIN JPA - Hibernate - java

Exception in thread "main" javax.persistence.EntityNotFoundException:
Unable to find CNPJ with id 00001388000307
I was reading jpa documentation, i read that this exception is thrown when it try to accesse(by the method getReference of EntityManger interface) and the entity doesn't exists
Thrown by the persistence provider when an entity reference obtained by EntityManager.getReference is accessed but the entity does not exist.
I have this entitys: Salesman e CNPJ. It's possible that exists many salesmen with the same CNPJ, in other words, a relationship #ManyToOne.
This relationship is working, OK.
But, when i try to execute the query
select r from Salesman r join fetch r.yearMonth left join fetch r.cnpj
to bring the salesmen with its yearMonth(it's working!) relationship and its CNPJ relationship, throws the Exception, when i try to do a LEFT JOIN, that i mentioned.
When i don't execute a LEFT JOIN, works great, all Salesmen with his CNPJs and nothin of Exceptions, BUUUUT, some salesmen don't have CNPJ nad i have to bring them too, there's a necessity to do a LEFT JOIN.
#Entity
public class Salesman{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#JoinColumn(name = "year_month")
#ManyToOne
private YearMonth yearMonth;
private String cnpjS;
#JoinColumn(name = "cnpj")
#ManyToOne
private CNPJ cnpj;
public AnoMes getYearMonth() {
return yearMonth;
}
public CNPJ getCnpj() {
return cnpj;
}
}
#Entity
public class CNPJ {
#Id
#Column(name = "CCG", length = 14)
private String ccg;
public String getCcg() {
return ccg;
}
}
The select generated by Hibernate:
select *
from salesman s
inner join yearmonth y on s.ano_mes = y.id
left outer join cnpj c on s.cnpjS = c.CCG
This consult returns this values, rcnpj is cnpj from Salesman and bcnpj is from CNPJ. Some Salesmen came with CNPJ NULL, i think that it's the problem. I don't think so.

Try to enable hibernate sql logging with <property name="show_sql">true</property> to see how real query (native, invoked on db) looks like, maybe there is a inner join after hibernate processing.
To change it you can try #Column(nullable=true) annotation for your relationship or #Fetch(FetchMode.SELECT) to see how real query will change.
The reason is that you have a reference to cnpj with ID 00001388000307, but such row of cnpj doesn't exist.
You can try to use #NotFound(action=NotFoundAction.IGNORE) to skip such error, but it is recommended to fix your database of handle a exception.

You are using the cnpj column on the table Salesman as both a foreign key and a value column. In that case #staszko032's suggestion using #NotFound(action=NotFoundAction.IGNORE) looks like will work as you expect
But I think you should refactor your model if possible. You could create a CNPJ entity always, in that case you won't have Salesman without a realation to CNPJ and could use INNER JOIN, or use 2 columns, one that will be used when the Salesman doesn't have a concrete related CNPJ (the value as string) and the other when it has (the foreign key)

Related

Hibernate - How to select just the foreign key value using Criteria Query without doing a Join?

So there is this similar (almost identical) question: How to select just the foreign key value using Criteria Query? but I need to avoid doing the join.
So I have two tables, one with a FK to the other
(Service)
id
name
account_id
(Account)
id
name
Service class has the FK defined this way:
#Entity
public class Service extends BaseDbEntity implements Serializable {
private static final long serialVersionUID = 1L;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
private Account account;
...
and what I want to do is query all the Service's that correspond to a given account, having the accountId, without doing a JOIN, because the id is already in the Service table.
Now, my criteria query looks like this:
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Service> criteria = cb.createQuery(Service.class);
Root<Service> root = criteria.from(Service.class);
criteria
.select(root)
.where(cb.equal(root.join("account").get("id"), accountId));
session.createQuery(criteria).getResultStream();
This ends up generating this query:
Hibernate: select service0_.id as id1_3_, service0_.name as name4_3_, service0_.account_id as account_id6_3_ from Service service0_ inner join Account account1_ on service0_.account_id=account1_.id where account1_.id=?
Which doesn't make sense.. it does a join on a field and then just creates a where clause for that field.
If I do:
root.get("account_id")
it just throws an exception saying the field is not available.
What is the correct way to avoid this?
Ok I just found the answer to my question:
Instead of doing
root.join("account").get("id")
I just needed to do:
root.get("account").get("id")
which avoids performing the JOIN.

Criteria API is not generating left outer join

I have 3 entities, infact many more joined together for brevity i'm skipping those and i'm using open jpa 2.2.2 and oracle 11g. Any thoughts what's going wrong here?
Entity SystemRules{
#OneToMany(mappedBy = "systemRule", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<ServiceActionMap> serviceActionMap;
}
Entity ServiceActionMap{
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "SYSTEM_RULE_ID")
private SystemRules systemRule;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "RFS_TYPE_ID", nullable = true)
private RfsTypeMap rfsType;
}
Entity RfsTypeMap{
#Id
#Column(name="RFS_TYPE_ID" ,nullable=false)
private BigDecimal rfsTypeId;
#Column(name="RFS_NAME")
private String rfsName;
}
Now, I am trying to order the result by RfsTypeMap.rfsName, i'm creating query using criteria builder in following manner
CriteriaQuery<SystemRules> query = cb.createQuery(SystemRules.class);
Root<SystemRules> root= query.from(SystemRules.class);
root.fetch(SystemRules_.serviceActionMap).fetch(ServiceActionMap_.rfsType, JoinType.LEFT);
My order by clause is like this
cb.desc(cb.upper(systemRules.get("serviceActionMap").get("rfsType").get("rfsName").as(String.class)));
Generate JPQL looks like, where i expect a left outer join clause between ServiceActionMap and RfsTypeMap but it's missing. Same gets translated in SQL and i miss those records which are having ServiceActionMap.rfsType as null value.
SELECT DISTINCT s FROM SystemRules s INNER JOIN FETCH s.serviceActionMap INNER JOIN FETCH s.serviceActionMap INNER JOIN FETCH s.ruleProperty INNER JOIN FETCH s.ruleProperty where ... ORDER BY UPPER(s.serviceActionMap.rfsType.rfsName)
I tried going over several answers here but no success, tried explicitly putting a where clause for ServiceActionMap.rfsType is null as suggested on few answers but it's getting ignored, since join happens before where evaluation. Somewhere this question openJPA outer join on optional many-to-one when have order by clause matches my scenario but not able to generate suggested JPQL through criteria API.
I found one related bug on apache jira https://issues.apache.org/jira/browse/OPENJPA-2318. But, not sure that's the case.
I see that every join is repeated twice and even the join alias is always referring to SystemRules. It might be that orderby has caused the repeating inner joins and we may need to explicitly use Join object to refer to extended column.
CriteriaQuery<SystemRules> query = cb.createQuery(SystemRules.class);
Root<SystemRules> root = query.from(SystemRules.class);
Join<SystemRules, ServiceActionMap> join1 = root.join(SystemRules_.serviceActionMap, JoinType.INNER);
Join<ServiceActionMap, RfsTypeMap> join2 = join1.join(ServiceActionMap_.rfsType, JoinType.LEFT);
query.orderBy(cb.desc(cb.upper(join2.get(RfsTypeMap_.rfsName))));

jpa query join fetch from a onetomany

I have the following 2 classes using JTA transaction type with openjpa & a derby embedded db. What I want is to get the parent Organisation & the requested WSpace in one query when I only have the WSpace id. I am quite new to JPA so am learning as I go and have been struggling with 'q2' query. I have been using queries 'q0' & 'q1' to debug and check the items do exist in the db. 'q0' returns 1 object as does 'q1', whereas 'q2' returns 0 objects
I have tried a variety of entity setups and different queries but nothing has worked yet.
Orignally the WSpace class did not have an Organisation field as it didn't seem necessary for persisting or selecting, but I added it (along with the mappedby parameter) incase it was needed for the query to work, but nothing has changed.
back to the original question how can I get this to work so it returns the parent object with the single child being requested
SELECT o FROM Organisation o JOIN FETCH o.spaces w WHERE w.id = :id
Here are my classes
#Entity
public class Organisation implements MyObjects
{
#Id
#NotNull
private Integer id;
private String name;
#OneToMany( mappedBy = "organisation",
cascade = { CascadeType.PERSIST, CascadeType.MERGE } )
private List<WSpace> spaces;
//getters/setter below
}
And
#Entity
public class WSpace implements MyObjects
{
#Id
#NotNull
private Integer id;
private String name;
#ManyToOne
private Organisation organisation;
#OneToMany
private List<Application> apps;
//getters/setter below
}
class DAO
{
...
public void foo( Integer id )
{
....
String q0 = "SELECT o FROM Organisation o WHERE o.id = 49068";
List<Organisation> res0 = em.createQuery( q0, Organisation.class ).getResultList();
String q1 = "SELECT w FROM WSpace w WHERE w.id = " + id;
List<WSpace> res1 = em.createQuery( q1, WSpace.class ).getResultList();
String q2 = "SELECT o FROM Organisation o "
+ "JOIN FETCH o.spaces w WHERE w.id = " + id;
List<Organisation> res2 = em.createQuery( q2, Organisation.class ).getResultList();
...
}
}
Have you tried to look in the logs for output of your q2 query?
I am learning JPA too and was dealing with Criteria and QL queries quite recently.
So after having pretty same problems with joins, I started checking logs and it was pretty clear, what the issues were, since logs showed up translated to SQL queries.
Another thing to look, how are you generating your Entities? I used Netbeans generating it for me. Also, many to many relations mignt have helper class generated too, I saw it in one of the projects.
Hope it helps..
The query you're looking for is probably this:
SELECT w FROM WSpace w LEFT JOIN FETCH w.organisation where w.id=:id
with query.setParameter("id", id); to bind the id parameter to the query. This effectively tells the persistence provider to fetch the WSpace.organisation relation while querying for WSpace entities in the same query. Using the LEFT [OUTER] keword (OUTER being optional) in front of the JOIN FETCH keywords tells your persistence provider to select WSpace objects even if there are no matching Organisation records for your WSpace.organisation relation.

Select subset of the list contained in an entity

Say I want to get all rows of the MyEntity that have an id lower than 10. This entity contains a list of Another entity. I would like this list to be fetched only by a subset of the listAnother. This subset containing only Another where the user contained in it is a specific one.
Basically in SQL it would be like this :
SELECT * FROM myentity m
LEFT JOIN another a
ON m.idTable=a.my_entity
AND a.user = "test1"
WHERE m.idTable < 10;
I didn't manage however to translate this query to jpql.
My entities being like this :
#Entity
public class MyEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idTable;
#OneToMany(mappedBy = "myEntity")
private List<Another> listAnother;
}
#Entity
public class Another implements Serializable {
#Id
private int idAnother;
// bi-directional many-to-one association to Thethread
#ManyToOne(fetch = FetchType.LAZY)
private MyEntity myEntity;
#ManyToOne(fetch = FetchType.LAZY)
private User user;
}
#Entity
public class User implements Serializable {
#Id
private String username;
}
In jpa I could do this :
SELECT m FROM MyEntity where m.idTable < 10;
And then for each entity I get from this list call this:
SELECT a FROM Another Where a.user.username=:'test' AND a.myEntity=:entity;
However I would like to do it all at once in one query. Can I do this with criteria ? I didn't take the time to learn it but if it's possible then I will.
JPQL and Critaria API are equal in terms of what you can express with them. What is possible with JPQL is possible with Criteria and vice versa.
With JPQL, you can simply combine your 2 queries into one in this way:
SELECT a FROM Another a Where a.user.username=:test AND a.myEntity.idTable < 10
You can use dot notation (.) to join multiple entities in the query, provided that the relationship is X-to-one. If you have X-to-many relationship, you need to use JPQL JOIN, which is not very complicated. Example with (LEFT) JOIN:
SELECT m FROM MyEntity m LEFT JOIN m.listAnother a Where a.user.username=:test AND m.idTable < 10
The result is of course not equal - in first case you will get list of Another entities and you can get MyEntity by a.myEntity, in the second case you will get list of MyEntity, which all have at least one Another entity with given user
In hibernate you can use Filters and FilterJoinTable. Here you can read how to do that. Similar problem was solved here.
You need to extend the logic which you applied to check the username (a.user.username=:'test') which was for many-to-one relation between anything and user by taking it one level up to myEntity and then using it for one-to-many relation as well -
SELECT m FROM MyEntity where m.idTable < 10 and (m.listAnother.user.username=:'test')
The join condition "m.listAnother.myEntity=:entity" wouldn't be needed now as in our query we have started from the specific myEntity and then moved down to listAnother.user.username .
I don't have the table definitions to try this query myself, exact SQL may require some tweaks - but logically it should work like the way I showed above, i.e. just the way you joined Another with User, the same way you can join MyEntity with Another by just traversing down the child listAnother.

#OneToOne-Relation with "is not null"

I'm using JPA2, Unitils, jUnit + other stuff.
My problem concerns two entities:
#Entity
public class CaseStuff implements Serializable {
....
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long caseStuffId;
#OneToOne(mappedBy = "CaseStuff")
private XCase xcase;
...
}
#Entity
public class XCase implements Serializable {
....
#OneToOne
#JoinColumn(name = "CASESTUFFID")
private CaseStuff caseStuff;
....
}
Both tables got the ID of the other table, so it could also be mapped the other way around.
In a jUnit-Test, Unitils inserts one CaseStuff record with no XCase. I confirmed, that it really is null.
BUT, then I use the following query:
"select s from CaseStuff s where s.xcase is null"
and it returns 0 CaseStuff objects. Doing the same with "is not null" returns the object, but when inspecting CaseStuff.xcase while debugging, it is clearly null.
Any idea, what's going awry here?
EDIT:
The SQL generated by Hibernate translates to
select
*
from
CaseStuff casestuff0_
where
(
casestuff0_.xcaseid is null
)
*Replaced all field names by *
EDIT2:
Before I changed it to a OneToOne-Relation, it was an unneccessary ManyToOne.
Previously the jUnit test had the query
"select s from CaseStuff s where not exists (select x from s.xcase x)"
This still works correctly for some reason, as if s.xcase was still a Set.
Thanks to all who try to figure it out with me.
As you defined your entities Xcase will have the foreign key
So Xcase table beside it's id will have caseStuff_id (or other name) as foreign key to the Xcase id.
Like in this image (make abstraction of the names)
In your case Person is Xcase and CaseStuff is PersonDetails
So probably you CaseStuff table (if it was generated by the persistence provider does not have a case id)
Please check on the db level to see how your tables are defined, structurally speaking.

Categories