Hibernate: create HQL Query with Attribute values from Sets - java

I want to create a HQL Query that can access Attributes of a Set of spezified Objects, let me explain via a short example:
Class Organization
public class Organization ...{
private int orgid;
private Set<DomainValue> languages = new HashSet<language>(0);
private Set<Address> adresses = new HashSet<Address>(0);
...
}
Class Address
public class Address implements java.io.Serializable {
private int addressId;
private String city;
private String postalCode;
private String streetName;
private String houseNumber;
...
}
Language
public class Orgunitlanguage implements java.io.Serializable {
private int orgLanguageId;
private Orgunit orgunit;
private Integer languageCd;
...
}
These examples are code snippets of working hibernate POJOs. So i have an organization that can have multiple addresses and languages.
I want the user to specify the search criteria, but limit them to one of each kind, so only one language, one postalcode etc.
lets say the user wants english organizations with a housenumber 22
so i would build a hql query like this:
"from organization o where o.languages.languageCd = 1 AND o.addresses.housenumber = 22"
Well and that dosen't work (illegal syntax) how do i access these Sets in the right way? Keep in mind i want to access a specific attribute and not just the whole object (which is really easy).
I can't seem to find a documentation that i understand so a little explaination would be nice.

Proper way to query on collections would be like this
from Organization o join o.languages l join o.addresses a where l.languageCd = 1 AND a.housenumber = 22
However, this query will return any organization that has at least one language with languageCd = 1 and at least one address with housenumber = 22. It will not filter out the languages and addresses that don't fit the criteria. Check this answer for a little more explanation on this.

Related

QueryDSL Predicate SetPath.any with multiple conditions

I have a simple entity with one to many relationship
#Entity // and other # stuff
public class Member {
#Id
private Long id;
private String name;
private List<Program> programs;
...
}
#Entity
public class Program {
#Id
private Long id;
private Long programName;
private ProgramType programType;
private Long programCost;
...
}
Now using QueryDSL, I would like to query
'All members enrolled in a program with programType = "FULLTIME" and programCost > $1000'
I used the following predicate
Predicate predicate = QMember.member.programs.any()
.programType.eq(ProgramType.FULLTIME)
.and(QMember.member.programs.any().programCost.gt(1000));
with JPARepository
memberRepository.findAll(predicate);
Now the problem is that the two queries are independent. It returns al members with at least one program of type 'FULLTIME' or at least one program of cost greater than 1000.
Desired result : Return members if he has at least one program that is of type FULLTIME and cost > 1000.
Got some help here : https://groups.google.com/forum/#!topic/querydsl/hxdejLyqXos
Basically the conditions on the program need to be in a separate subQuery (a JPASubquery instance)
QProgram program = QProgram.program
JPASubQuery subQuery = new JPASubQuery();
subQuery.from(program)
.where(program.programType.eq(ProgramType.FULLTIME),
program.programCost.gt(1000));
Predicate predicate = QMember.member.name.eq("John")
.and(subQuery.exists());
memberRepository.findAll(predicate);
As mentionned by #Shahbour, this is not working anymore with QueryDsl 4.x+.
I had a similar case (except that my entities are bidirectionnal), and I've solved it with this :
QProgram program = QProgram.program;
QProgram member = QProgram.member;
Predicate predicate = JPAExpressions
.selectOne()
.from(program)
.where(program.member.id.eq(member.id),
program.programCost.gt(1000),
program.programType.eq(ProgramType.FULLTIME))
)
.exists();
memberRepository.findAll(predicate);

Spring data Neo4j fetch relationships

I am using spring-data-neo4j V4 and look for solution how to fetch entities which are not directly connected to the loaded entity. To explain:
I do have 3 entities in my neo4j database.
#NodeEntity(label="membership")
public class Membership extends AbstractEntity{
public Membership(){ }
private String membershipId;
#Relationship(type = "IN_YEAR", direction = Relationship.OUTGOING)
private Set<Year> year = new HashSet<>();
//getter+setter
}
#NodeEntity(label="year")
public class Year extends AbstractEntity{
public Year(){}
private String name;
private String membershipId;
#Relationship(type = "IN_MONTH", direction = Relationship.OUTGOING )
private Set<Month> month = new HashSet<>();
//getter+setter
}
#NodeEntity(label="month")
public class Month extends AbstractEntity{
private String name;
//getter+setter
}
When i call my MembershipRepository and load a Membership by Id:
membershipRepository.findByMembershipId(id);
the year entities will be fetched but the month entities not.
Can anybody tell what is the best or recommended way to load the month entities when loading the membership entity? As written in http://docs.spring.io/spring-data/neo4j/docs/current/reference/html/ the #Fetch is obsolete since version 4 so I need another solution.
EDIT:
I read in http://docs.spring.io/spring-data/neo4j/docs/current/reference/html/ the workaround for fetch, just use the load methods from the Neo4jTemplate.
So I load the months for every year by:
Set<Year> fetchedYear = new HashSet<>();
for(Year year : ms.getYear()){
fetchedYear.add(neo4jTemplate.load(Year.class, year.getId(), 1));
}
ms.setYear(fetchedYear);
But is there a better solution?
The first option would be to use loadByProperty and set the loading depth to 2.
Example:
neo4jTemplate.loadByProperty(Membership.class, "membershipId", value, 2);
This is available for SDN-4.1.0-Snapshot
But if you do not want to load a Membership with depth 2 because too much of your graph will be loaded (from other relationships) then I think you could construct a cypher query (using OPTIONAL MATCH), execute it with the neo4jTemplate and retrieve the Object which will then be automatically mapped due to the “smartObjectMapping".
Example:
String query = "MATCH (n:Membership{membershipId:{id})-[r]-(m) OPTIONAL MATCH (m:Year)-[e]-(x) RETURN n,r,m,e,x";
Map<String,Object> map = new HashMap<>();
map.put("id",value);
Result result = neo4jTemplate.query(query,map);
now n in the Result should contain all mapped relationships

Spring Hibernate: SQLQuery involving mapped entities

I have Hibernate generated classes that contain other classes -
public class BookLoans implements java.io.Serializable {
private BookLoansId id;
private Borrower borrower;
private LibraryBranch libraryBranch;
private Book book;
private Date dateOut;
private Date dueDate;
}
where BookLoansId is -
public class BookLoansId implements java.io.Serializable {
private int bookId;
private int branchId;
private int cardNo;
}
which are primary keys in the tables Book, LibraryBranch and Borrower respectively. When I run this query -
sessionFactory.getCurrentSession().createSQLQuery(
"select * from library.tbl_book_loans l where cardNo = 4");
Hibernate returns a list of Object[] elements. If I try to iterate through this list, I get null objects. I've tried a couple of different methods from here and here.
Is there any way to find out how the objects are arranged within each Object[]?
To directly map the query result to an entity objct use addEntity(BookLoans.class);
sessionFactory.getCurrentSession().createSQLQuery(
"select * from library.tbl_book_loans l where cardNo = 4")
.addEntity(BookLoans.class);
See the docs(16.1.2. Entity queries):
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querysql.html
However the result of nulls you get from your attempt is strange. Hibernate should give you List of Objects arrays where each Object array represents the fields in one row of the result set. Check if the query actualy returns something.
I solved this by using HQL:
from library.tbl_book_loans where borrower.cardNo = 4
Hibernate now correctly populates all mapped entities.

Is it possible to link objects on a unique column?

I'm using Hibernate 3.2.7.ga and I'm wondering if the following is possible.
Let's say there are 3 objects: Person, Town and Mayor.
When registering a Person in the application, you're asked to enter his or her town of residence. This field is saved as a String.
In another part of the application, you can register a Town (with it's name, number of inhabitants, etc.). After the Town is registered, you can add a Mayor to this town.
However, it is not desired to create a Town object for every town that is entered with a Client. An object is only desired when a Mayor needs to be registered.
I'm wondering if, just bij using the String field in Person, you can get the Mayor of the Town the Person lives in.
I'm thinking along these lines of code:
public class Client.java
{
#Id
public Long id;
#Column(nullable = true, ??? )
public String townOfResidence;
public Mayor getMayor()
{
...
}
}
public class Town.java
{
#Id
public Long id;
#Column(nullable = false, unique = true)
public String name;
#OneToOne
public Mayor mayor;
}
I just tried thinking along the following lines:
#Transient
private Town townObject;
#ManyToOne(fetch = FetchType.LAZY, cascade = javax.persistence.CascadeType.ALL, targetEntity = Town.class, optional = true)
#JoinColumn(referencedColumnName = "town")
public Town getTown()
{
return townObject;
}
It is more an ERD issue than an ORM one.
Either you have a relationship between Person and Town or you don't. If you have, you can only select values in the reference attribute that are in keys in the referenced table, or null (if valid). If you don't have the relationship, you have no restrictions.
Of course, you do not need to have a relationship to try to mix them in a query/JPQL. Without relationship, your program may offer the list of Town as possible values for the Person town, without forcing them to pick one. Or you may do something like
SELECT t FROM Town t WHERE t.name = ?
And pass the person town there. Of course too, then there is no security that it will be not null.
An alternative approach might be having two columns, one as a reference to a Town (allowing null) and other as a free text. If the town is in the table you use the reference, if it is not use the String. Of course, this complicates your program logic considerably.
With this design, you'll need to use a query to get the mayor of the town of the person:
select mayor from Town town
inner join town.mayor mayor
where town.name = :theTownOfResidenceOfTheClient
This query will have to be executed as part of the method of a DAO/Repository class. The mayor can't be available in a getMayor() method of the Client object.

Left join bringing 2 different objects

I could not make a better title, if anyone can do it please, help me out! Same for tags.
I've made a JPQL to bring me one Object with a List of other Objects.
The thing that's happening is.
I've got 2 items in Novidade(DB).
I've got 2 items in ComentarioNovidade(DB).
1 of the items from Novidade, connects to all 2 items from ComentarioNovidade. The other has no ComentarioNovidade related.
JPQL returns a List of Novidade (it's supposed to be)
I'm trying to make it return one Novidade with all ComentarioNovidade in it if it has any.
It's returning 3 Objects containing Novidade and ComentarioNovidade separated.
My JPQL is like this:
from Novidade as n left outer join n.comentariosNovidade
The class Novidade:
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="CodNovidade")
private Integer codNovidade;
#Column(name="Mensagem")
private String mensagem;
#Column(name="CodigoCidade")
private int codCidade;
#Column(name="CodigoBairro")
private int codBairro;
#Column(name="MesmoBairro")
private String mesmoBairro;
#OneToMany
#JoinColumn(name="CodNovidade")
private List<ComentarioNovidade> comentariosNovidade;
The class ComentarioNovidade:
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="CodComentarioNovidade")
private Integer codComentarioNovidade;
#Column(name="Comentario")
private String comentario;
#ManyToOne
#JoinColumn(name="CodNovidade")
private Novidade novidade;
#ManyToOne
#JoinColumn(name="CodUsuario")
private Usuario usuario;
A friend helped me out with that.
My JPQL ended up like this:
select distinct n from Novidade as n left outer join fetch n.comentariosNovidade

Categories