Custom #Query in Spring Data Repository through multiple entities - java

I have 4 JPA Entities as following:
Entity Farm :
#Entity
public class Farm implements Serializable {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idFarm;
private String nameFarm;
}
Entity SAU :
#Entity
public class SAU implements Serializable {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idSau;
private String nameSau;
#OneToOne
#JoinColumn(name="farm_id")
private Farm farm;
}
Entity Part :
#Entity
public class Part implements Serializable {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idPart;
private String namePart;
#ManyToOne
#JoinColumn(name = "sau_id")
private Sau sau;
}
Entity Cult :
#Entity
public class Cult implements Serializable {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idCult;
private String nameCult;
#OneToOne
#JoinColumn(name = "part_id")
private Part part;
}
I need to retrieve a Collection of Cult objects Where farm_id = x, I obviously can't do it by using the convention naming of methods like :
public Collection<Cult> = findCultByPartBySauByFarmIdFarm(Long idFarm);
I can't figure out how to write the custom #Query either for this case in Spring Data Repository.

Another version without explicit joins.
#Query("select c from Cult c where c.part.sau.farm.idFarm = ?1")
public Collection<Cult> findCultByFarmId(Long idFarm);
I usually prefer to use this as I let the underline implementation to deal with the joins for me.

Try:
#Query("select c from Cult c join c.part p join p.sau s join s.farm f where f.idFarm = ?1")
public Collection<Cult> = findCultByFarmId(Long idFarm);

Related

JPA Embeddable bidirectional

What's the correct way to create bidirectional 1to1 mapping using Embeddable annotation? This one throws error
"EmpId has no persistent id property: Emp.id"
#Entity
public class Per implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "per_id")
private Long id;
#OneToOne
#JoinColumn(name = "per_id", referencedColumnName = "emp_id")
private Emp emp;
}
#Embeddable
public class EmpId implements Serializable {
private static final long serialVersionUID = 1L;
#OneToOne(mappedBy = "emp")
private Per per;
}
#Entity
public class Emp implements Serializable {
#EmbeddedId
private EmpId id;
}
I'd like to operate entities like
per.getEmp();
emp.getId().getPer();

JPA one to one mapping creates multiple query when child entity is not found

I have a parent entity 'contracts' that has a one-to-one relation with another entity 'child-contract'. the interesting thing is that the mapping field ('contract_number')id not a primary key-foreign key but is rather a unique field in both the tables. Also it is possible for a contracts to not have any child contract altogether. With this configuration I have observed hibernate to generate 1 additional query every time a contracts does not have a child-contract. I filed this behavior very strange. Is there a way to stop these unnecessary query generation or have I got something wrong.
below is a piece of my code configuration.
#Data
#Entity
#Table(name = "contracts")
public class Contracts implements Serializable {
#Id
#JsonIgnore
#Column(name = "id")
private String id;
#JsonProperty("contract_number")
#Column(name = "contract_number")
private String contractNumber;
#OneToOne(fetch=FetchType.EAGER)
#Fetch(FetchMode.JOIN)
#JsonProperty("crm_contracts")
#JoinColumn(name = "contract_number", referencedColumnName = "contract_number")
private ChildContract childContract ;
}
#Data
#NoArgsConstructor
#Entity
#Table(name = "child_contract")
#BatchSize(size=1000)
public class ChildContract implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#JsonProperty("id")
#Column(name = "id")
private String id;
#JsonProperty("contract_number")
#Column(name = "contract_number")
private String contractNumber;
}
Please help.
Thank-you
You can use NamedEntityGraph to solve multiple query problem.
#NamedEntityGraph(name = "graph.Contracts.CRMContracts", attributeNodes = {
#NamedAttributeNode(value = "crmContract") })
Use this on your repository method as
#EntityGraph(value = "graph.Contracts.CRMContracts", type = EntityGraphType.FETCH)
// Your repo method in repository

JPQL: Difference between EclipseLink and Hibernate

I already asked about my situation and didn't find a proper solution. After some additional search I think I know the source problem although don't know how to resolve it. As mentioned I have:
#Table(name = "role__parent")
#IdClass(RoleAssociationKey.class)
#Data
public class RoleAssociation implements Serializable {
#Id
#JoinColumn(name = "has_parent_role_id")
private Role node;
#Id
#JoinColumn(name = "is_parent_for_role_id")
private Role parent;
...
}
#Data
class RoleAssociationKey implements Serializable {
private static final long serialVersionUID = 1L;
private int node;
private int parent;
}
and I have
#Table(name = "role")
#Data
public class Role implements IRole {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany(mappedBy = "node", orphanRemoval = true, cascade = { CascadeType.ALL })
private List<RoleAssociation> parentRoles;
...
Up to this point I think nothing special. I have the query:
#NamedQuery(name = "Role.findParents", query =
"SELECT r FROM Role r JOIN RoleAssociation ra ON r.id = ra.parent.id WHERE ra.node.id = :id")
with the purpose to all set parents. When I compile it Hibernate complainsleft and right hand sides of a binary logic operator were incompatible [integer : component[node,parent]]
Since the statement works in EclipseLink I have no clue how to change it into a working Hibernate one. Help would be highly appreciated.
After some struggels I finally figured the root cause of this problem. I'm aware that the SQL might be improved nevertheless I fail at other similar spots.
Hibernate requires to have a matching pair for #OneToMany relation.
In my query I refer to the parent of my role. The solution is
#Data
public class RoleAssociation implements Serializable {
#Id
#JoinColumn(name = "has_parent_role_id")
#ManyToOne // <<<<==== rerequired for Hibernate
private Role node;
#Id
#JoinColumn(name = "is_parent_for_role_id")
#ManyToOne // <<<<==== rerequired for Hibernate
private Role parent;
I have no clue why Hibernate complains while EclipseLink can fetch the required information. Nevertheless with this additional annoation the code works!

jpa one-to-many self reference is fetching all levels

I'm trying to create a social app service. I have user with confirmed or nonconfirmed relationships.
When I load UserA, the result look like belove.
"result":{
"idUser":"UserA",
"unconFriendships":[
{
"idUser":"UserB",
"unconFriendships":[
{
"idUser":"UserC",
"unconFriendships":[
...
While it has to be look like
"result":{
"idUser":"UserA",
"unconFriendships":[
{
"idUser":"UserB",
"unconFriendships":null //only one level have to fetched
....
I thought that this was because jackson json library, I debbuged the code. Before serialization, I inspected userA object and I saw that userA.unconFriendships.userB.unconFriendships was not null and with size bigger than 0.
Nearly it has been 12 hours, still couldn't solve the problem. Please help me to solve this. Thanks in advence.
Here is UserEntity.java
#Entity
#Table(name="aduser",uniqueConstraints=#UniqueConstraint(columnNames = {"idUser","nmEmail"}))
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="cdUser")
public class UserEntity extends BaseEntity {
protected static final long serialVersionUID = 8864033727886664353L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "admin_seq")
#SequenceGenerator(name = "admin_seq", sequenceName = "CDUSER_SEQUENCE", allocationSize = 1)
#Column(name="cdUser")
private long cdUser;
#OneToMany(mappedBy = "owner", targetEntity=Friendship.class)
#JsonProperty
protected Set<UnconfirmedFriendship> unconFriendships;
#OneToMany(mappedBy = "owner", targetEntity=Friendship.class)
#JsonProperty
protected Set<UnconfirmedFriendship> conFriendships;
...
Friendship.java
#Entity
#Table(name="aduserfriend")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "verified")
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="friend_cduser",scope=UserEntity.class)
public abstract class Friendship extends BaseEntity{
protected static final long serialVersionUID = -670863816551430192L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "cdFriendship")
private long cdFriendship;
#ManyToOne
#JsonIgnore
#JoinColumn(name = "owner_cduser")
protected UserEntity owner;
#ManyToOne
#JoinColumn(name = "friend_cduser")
protected UserEntity friend;
#Column(name = "verified",insertable=false,updatable=false)
private boolean verified;
...
UnconfirmedFriendship.java and ConfirmedFriendship.java
#Entity
#DiscriminatorValue(value = "0")//this value is 1 for Confirmed relationship
public class UnconfirmedFriendship extends Friendship {
private static final long serialVersionUID = 57796452166904132L;
}

HQL error in named query subselect

This HQL results in the tremendously helpful "error in named query" message
"FROM courseform c WHERE c.application.application IN
(SELECT a.application FROM application a WHERE a.applicant=: applicant)"
The CourseForm has a OneToOne unidirectional relationship with the Application (this could potentially be made bidirectional if it would help). Application in turn has the same unidirectional OneToOne relationship with the Applicant. One applicant can have many applications.
Here are the (abridged) definitions
CourseForm
#Entity
#NamedQueries({
#NamedQuery(name = "CourseForm.findByApplicant",
query = "FROM courseform c WHERE c.application.application IN
(SELECT a.application FROM application a WHERE a.applicant=: applicant)") })
public class CourseForm implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long id;
#Enumerated(EnumType.STRING)
private Career career;
private String academicPlan;
private String courseName;
#Enumerated(EnumType.STRING)
private ModeOfAttendance modeOfAttendance;
#OneToOne
#JoinColumn(name = "application_fk")
private Application application;
...
}
Application
#Entity
public class Application implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long applicationNumber;
#OneToOne
#JoinColumn(name = "applicant_fk")
private Applicant applicant;
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
private LocalDateTime lastUpdate = LocalDateTime.now();
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
private LocalDateTime submitted = null;
public Application() {
}
Applicant
#Entity
#NamedQueries({ #NamedQuery(name = "Applicant.findByApplicantID",
query = "FROM Applicant a WHERE a.applicantID= :applicantID") })
public class Applicant implements Serializable {
private static final long serialVersionUID = -7210042752148566673L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long id;
private String applicantID;
Applicant() {
}
Ok, according to Mark, right answer is
FROM courseform c WHERE c.application.applicant =: applicant
I think the error is with FROM courseform c WHERE c.application.application.You have used c.application.application in where clause
It should be FROM courseform c WHERE c.application
You can change to:
FROM courseform c WHERE c.application.applicationNumber IN (SELECT a.applicationNumber FROM application a WHERE a.applicant=: applicant)

Categories