i have a problem with named query in my project. I have 2 entities with OneToOne relation.
#Entity
#Table(name = "SL_BRANCH_PARAMS")
public class BranchParams implements Identifiable {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "SL_BRANCH_PARAM_SEQ_GEN")
#SequenceGenerator(name = "SL_BRANCH_PARAM_SEQ_GEN", sequenceName = "SL_BRANCH_PARAM_SEQ")
private Long id;
#JoinColumn(name = "INTEREST_ACCOUNT_ID")
#OneToOne(fetch = FetchType.EAGER)
private AccountDef interestAccount;
}
and second class with named query
#Entity
#Table(name = "SL_ACCOUNT_DEF")
#NamedQueries({
#NamedQuery(name = "AccountDef.getAvaibleInterestAccountsForBranch",
query = "SELECT ad FROM AccountDef ad LEFT JOIN FETCH ad.branchParamsInterest WHERE ad.branchParamsInterest = NULL ORDER BY ad.id ASC"),
})
public class AccountDef implements Identifiable {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "SL_ACCOUNT_DEF_SEQ_GEN")
#SequenceGenerator(name = "SL_ACCOUNT_DEF_SEQ_GEN", sequenceName = "SL_ACCOUNT_DEF_SEQ")
private Long id;
#OneToOne(fetch = FetchType.EAGER, mappedBy = "interestAccount")
private BranchParams branchParamsInterest;
}
When i execute the named query I get this query to database
select
accountdef0_.ID as ID1_10_0_,
branchpara1_.ID as ID1_13_1_,
branchpara1_.INTEREST_ACCOUNT_ID as INTERES16_13_1_
from
SL_ACCOUNT_DEF accountdef0_
left outer join
SL_BRANCH_PARAMS branchpara1_
on accountdef0_.ID=branchpara1_.INTEREST_ACCOUNT_ID
where
accountdef0_.ID is null //this is incorrect
order by
accountdef0_.ID ASC
which is not correct because it gives me no rows as it checks if the ID in AccountDef is null instead in BranchParams.
The correct query should look like this
select
accountdef0_.ID as ID1_10_0_,
branchpara1_.ID as ID1_13_1_,
branchpara1_.INTEREST_ACCOUNT_ID as INTERES16_13_1_
from
SL_ACCOUNT_DEF accountdef0_
left outer join
SL_BRANCH_PARAMS branchpara1_
on accountdef0_.ID=branchpara1_.INTEREST_ACCOUNT_ID
where
branchpara1_.ID is null //this is correct
order by
accountdef0_.ID ASC
and such query returns the rows i want. And the question from me is, why named query checks null id value for AccountDef instead for BranchParams?
Perhaps something like this?
#NamedQuery(name = "AccountDef.getAvaibleInterestAccountsForBranch",
query = "SELECT ad FROM AccountDef ad LEFT JOIN FETCH ad.branchParamsInterest bp WHERE bp.interestAccount = NULL ORDER BY ad.id ASC")
Related
I have 2 entities with a ManyToMany association between them - FeedbackApp & FeedbackAppProfile and each of them has a tenant-id FK to Tenant entity.
FeedbackApp entity:
public class FeedbackApp {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "tenant_id")
private Tenant tenant;
/*
Marked as the owner side.
*/
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "feedbackApp_profile_mapping",
joinColumns = #JoinColumn(name = "feedbackApp_id"),
inverseJoinColumns = #JoinColumn(name = "profile_id"))
Set<FeedbackProfile> profiles;
}
The FeedbackProfile entity:
public class FeedbackProfile {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "tenant_id")
private Tenant tenant;
#ManyToMany(mappedBy = "profiles", fetch = FetchType.EAGER)
Set<FeedbackApp> feedbackApps;
}
The feedbackApp_profile_mapping join table has 2 columns and looks like this:
My question: I need to create a query that gets all feedback apps for a specific feedback profile and tenant id. Is it possible to get it with Hibernate/JPA OR I have to manually query my join table?
Let Jpa worry about the optimal Sql query to generate. Your Jpa/criteria/specification query should be something like
select fp.feedbackApps from FeedbackProfile fp LEFT JOIN FETCH fp.feedbackApps where fp.id=:feedback_profile_id and fp.tenant.id=:tenant_id
Since you are asking about efficiency, better remove fetch = FetchType.EAGER from the two many-to-many mappings and use join fetch or named entity graphs to do the joins only when you need to.
Thanks to #GabiM direction, I created a join fetch query which did the job for what I needed:
#Query(value = "SELECT f FROM FeedbackApp f JOIN FETCH f.profiles p WHERE p.id = ?1 AND p.tenant.id = ?2")
Set<FeedbackApp> getFeedbackAppsByProfileId(long profileId, long tenantId);
I have three entities: EntityA maps to table_a, EntityB maps to table_b, and Catalog maps to catalog. In the database, there's a many-to-many table between table_b and catalog, b_catalog_xref. EntityB has a field: Long aId, and a field: List<Catalog> catalogs. The Catalog entity has a field: String name. Given a list of IDs for EntityB, and a string representing a catalog name, I need to retrieve all occurrences of EntityA whose ID matches that of an EntityB's aId, and where the given catalog name matches that of one of EntityB's catalogs.
I've successfully grabbed the correct data via regular SQL, but I'm struggling to recreate the query in JPQL. Here's the SQL query:
SQL:
SELECT
*
FROM
table_a a
WHERE
a.table_a_id in (
SELECT
b.table_a_id
FROM
table_b b
INNER JOIN b_catalog_xref bcx ON bcx.table_b_id = b.table_b_id
INNER JOIN catalog c ON c.catalog_id = bcx.catalog_id
WHERE
c.catalog_name = 'Example Catalog Name'
);
Java:
#Entity
#Table(name = "table_a")
public class EntityA {
#Id
#Column(name = "table_a_id")
private Long aId;
...
}
#Entity
#Table(name = "table_b")
public class EntityA {
#Id
#Column(name = "table_b_id")
private Long bId;
#Column(name = "table_a_id")
private Long aId;
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH})
#JoinTable(name = "b_catalog_xref",
joinColumns = {#JoinColumn(name = "table_b_id")},
inverseJoinColumns = {#JoinColumn(name = "catalog_id")})
#Fetch(FetchMode.SELECT)
#OrderBy("name ASC")
List<Catalog> catalogs
...
}
#Entity
#Table(name = "catalog")
public class Catalog {
#Id
#Column(name = "catalog_id")
private Long catalogId;
#Column(name = "catalog_name")
private String name;
...
}
Yes, you can use something like
TypedQuery<TableA> q = entityManager.createQuery
("Select a from TableA a where a.aId in(Select b.aId from TableB b " +
"join b.catalogs c where c.name=:name)", TableA.class);
q.setParameter("name", "some2");
I advise you to consider creating a relationship between tables A and B instead of copying the key of table A to table B
#Entity
#Table(name = "table_b")
public class EntityB {
...
// #Column(name = "table_a_id")
// private Long aId;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "table_a_id")
private TableA tableA;
...
}
Then JPQL will look like:
TypedQuery<TableA> q = entityManager.createQuery
("Select distinct b.tableA from TableB b join b.catalogs c " +
"where c.name=:name", TableA.class);
q.setParameter("name", "some2");
Pay attention to the keyword distinct, it removes all duplicates in the result list.
And do not use FetchType.EAGER unless absolutely necessary, use FetchType.LAZY.
I have two models Quality and ExpertsData:
#Entity(name = "QualityDepartmentData")
#Table(name = "quality")
public class QualityDepartmentData {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "qualityId")
private List<ExpertsData> ListOfExpertsData;
#Entity(name = "ExpertsData")
#Table(name = "experts")
public class ExpertsData {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private Long qualityId;
private Integer expertId;
I need to fetch list of QualityDepartmentData by the expertId. Right now I can do it by native MySQL query, like this:
#Query(value = "SELECT * FROM quality INNER JOIN experts ON quality.id = experts.quality_id WHERE experts.expert_id = ?1", nativeQuery = true)
Page<QualityDepartmentData> findAllForExpertId(long id, Pageable pageable);
That is working, but the problem is that the native query can't be dynamically sorted, so I need to write query in JPQL for ability to use org.springframework.data.domain.Pageable.
Can't find any examples for such event in official JPA docs. Also I tryed many vatiants like this, but it's not working:
#Query(value = "SELECT d FROM QualityDepartmentData d INNER JOIN ExpertsData c ON d.id = c.qualityId WHERE c.expertId = ?1")
#Query(value = "SELECT distinct q FROM QualityDepartmentData q JOIN q.ListOfExpertsData e WHERE e.expertId = ?1")
Page<QualityDepartmentData> findAllForExpertId(Integer id, Pageable pageable);
That is working. Thanks for link to example to JB Nizet!
I am new to Hibernate and really need help from you guys....
I have following class: UserActionPerUserResult
#Entity
#Table(name = "user_action_per_user_result")
public class UserActionPerUserResult {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "user_email", nullable = false)
private String userEmail;
#ManyToOne
#JoinColumn(name = "user_action_id", nullable = false)
private UserAction userAction;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name="user_action_per_user_result_email_message",
joinColumns={#JoinColumn(name="user_action_per_user_result_id", referencedColumnName="id")},
inverseJoinColumns={#JoinColumn(name="email_message_id", referencedColumnName="id")})
#JsonIgnore
private List<EmailMessage> emailMessages;
....getters/setter....
}
In MYSQL, the UserActionPerUserResult is one table and for email Messages, there is another table called as UserActionPerUserResultEmailMessage which has email messages associate with id of the table UserActionPerUserResult.
I have all the data stored in the MySQL table, however I am not able to query it. I need to write a query to fetch the list of emailMessages. I am trying the following, but it is throwing exception.
TypedQuery<UserActionPerUserResult> messagesQuery = entityManager.createQuery(
"SELECT e from UserActionPerUserResult e JOIN UserActionPerUserResult.emailMessages e1 WHERE e.id = 1 and e.userAction = 1", UserActionPerUserResult.class);
List<UserActionPerUserResult> resultList = messagesQuery.getResultList();
Try writing the query like this:
TypedQuery<UserActionPerUserResult> messagesQuery = entityManager.createQuery(
"SELECT e from UserActionPerUserResult e JOIN FETCH e.emailMessages em WHERE e.id = 1 and e.userAction.id = 1", UserActionPerUserResult.class);
List<UserActionPerUserResult> resultList = messagesQuery.getResultList();
The join is using the root entity alias
The userAction.id is used against userAction, when matching against a numerical value
I was wondering if you guys could help me with an OpenJPA query I am trying to write.
I have an ItemEntity...
#Entity(name = "item")
public class ItemEntity implements java.io.Serializable {
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "itemid")
#TableGenerator(name = "itemid", table = "items_sequence", allocationSize = 1)
private Long id;
#ManyToOne
private ImportPayloadEntity importPayloadEntity;
And a ImportPayloadEntity...
#Entity(name = "import_payload")
public class ImportPayloadEntity implements java.io.Serializable{
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "importpayloadid")
#TableGenerator(name = "importpayloadid", table = "import_payload_sequence", allocationSize = 1)
private Long id;
#Column(name = "PROCESSED_IND")
private String processedInd;
I am trying to select from my item entity joining back to my import payload entity to ensure that the processedInd is equal to 'N'.
I can't quite get the correct syntax. I've tried a few things but here is my latest attempt..
#NamedQuery(name = "queryItems", query = "SELECT c1, c2 FROM item c1 INNER JOIN c1.importPayloadEntity c2 WHERE c2.processedInd='N'")
This gives me...
Unknown column 't0.IMPORTPAYLOADENTITY_ID' in 'on clause' {prepstmnt 1719904819 SELECT t0.id, t1.id, t1.FILENAME, t1.LOAD_DATETIME, t1.IMPORT_PAYLOAD_BODY, t1.IMPORT_PAYLOAD_TYPE, t1.PROCESSED_DATETIME, t1.PROCESSED_IND FROM item t0 INNER JOIN import_payload t1 ON t0.IMPORTPAYLOADENTITY_ID = t1.id WHERE (t1.PROCESSED_IND = ?)} [code=1054, state=42S22]
Appreciate your help.
You can try select i from Item i where i.importPayloadEntity.processedInd = 'N'