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);
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
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.
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
I have a legacy database I'm trying to redesign into the 21st century. One of the existing data structures involves a particular class which contains a 2-dimensional matrix of values. If I were to reverse-engineer this class from the database, I'd end up with a series of attributes like:
private BigDecimal NODE_1_MATRIX_POS_1_1;
private BigDecimal NODE_1_MATRIX_POS_1_2;
and so on. Since this is a 6x6 matrix, there are a lot of such columns.
I've been looking for a better way, but I'm not sure I'm there. What I'd like to do is something like this:
#Entity
public class TestClass {
#Id
private long id;
#CollectionOfElements
#JoinTable(
name="MATRIX_DATA",
joinColumns=#JoinColumn(name="ENTRY_ID"))
private List<List<BigDecimal>> matrix;
But this fails:
org.hibernate.MappingException: Could not determine type for: java.util.List, at table: MATRIX_DATA, for columns: [org.hibernate.mapping.Column(element)]
Rather than just trying to fix the error, I thought I'd ask around and try to find the right approach to solving this mapping challenge. Has anyone found success and satisfaction mapping multidimensional arrays via JPA?
Rather than just trying to fix the error, I thought I'd ask around and try to find the right approach to solving this mapping challenge. Has anyone found success and satisfaction mapping multidimensional arrays via JPA?
AFAIK, nested collections are not supported by standard JPA. The JPA wiki book has a good section on this topic (I'm quoting only a part of it):
Nested Collections, Maps and Matrices
It is somewhat common in an object
model to have complex collection
relationships such as a List of
Lists (i.e. a matrix), or a Map of
Maps, or a Map of Lists, and so
on. Unfortunately these types of
collections map very poorly to a
relational database.
JPA does not support nested collection relationships, and normally
it is best to change your object model
to avoid them to make persistence and
querying easier. One solution is to
create an object that wraps the nested
collection.
For example if an Employee had a
Map of Projects keyed by a
String project-type and the value a
List or Projects. To map this a
new ProjectType class could be
created to store the project-type and
a OneToMany to Project.
...
And that would be my suggestion. For example:
#Entity
public class TestClass {
#Id
private long id;
#OneToMany(mappedBy="testClass")
private List<MatrixRow> matrix;
}
Where MatrixLine would be (omitting many details):
#Entity
public class MatrixRow {
#Id
private long id;
#ManyToOne
private TestClass testClass;
#CollectionOfElements
private List<BigDecimal> row;
}
Or maybe you could use a custom user type (I'm not too sure how this would work).
Or (after all, you're already using non portable annotations) have a look at this question to see how you could extend Hibernate:
How do I map a nested collection, Map<Key,List<Values>>, with hibernate JPA annotations?
Hibernate Types project
You can map a PostgreSQL multidimensional array using the Hibernate Types project.
You can choose to use a Java array on the entity attribute side or use List.
Database table
For exmaple, assuming you have the following plane database table:
CREATE TABLE plane (
id INT8 NOT NULL,
name VARCHAR(255),
seat_grid seat_status[][],
PRIMARY KEY (id)
)
Where the seat_status is a PostgreSQL enum:
CREATE TYPE seat_status
AS ENUM (
'UNRESERVED',
'RESERVED',
'BLOCKED'
);
JPA entity
You can map the seatGrid column using the EnumArrayType:
#Entity(name = "Plane")
#Table(name = "plane")
#TypeDef(
name = "seat_status_array",
typeClass = EnumArrayType.class
)
public static class Plane {
#Id
private Long id;
private String name;
#Type(
type = "seat_status_array",
parameters = #org.hibernate.annotations.Parameter(
name = "sql_array_type",
value = "seat_status"
)
)
#Column(
name = "seat_grid",
columnDefinition = "seat_status[][]"
)
private SeatStatus[][] seatGrid;
//Getters and setters omitted for brevity
public SeatStatus getSeatStatus(int row, char letter) {
return seatGrid[row - 1][letter - 65];
}
}
So, you need to declare the appropriate Hibernate Type to use. For enums, you need to use the EnumArrayType:
#TypeDef(
name = "seat_status_array",
typeClass = EnumArrayType.class
)
The #Type annotation allows you to pass parameters to the Hibernate Type, like the SQL array class:
#Type(
type = "seat_status_array",
parameters = #org.hibernate.annotations.Parameter(
name = "sql_array_type",
value = "seat_status"
)
)
Testing time
Now, when you persist the following Post entity:
entityManager.persist(
new Plane()
.setId(1L)
.setName("ATR-42")
.setSeatGrid(
new SeatStatus[][] {
{
SeatStatus.BLOCKED, SeatStatus.BLOCKED,
SeatStatus.BLOCKED, SeatStatus.BLOCKED
},
{
SeatStatus.UNRESERVED, SeatStatus.UNRESERVED,
SeatStatus.RESERVED, SeatStatus.UNRESERVED
},
{
SeatStatus.RESERVED, SeatStatus.RESERVED,
SeatStatus.RESERVED, SeatStatus.RESERVED
}
}
)
);
Hibernate will issue the proper SQL INSERT statement:
INSERT INTO plane (
name,
seat_grid,
id
)
VALUES (
'ATR-42',
{
{"BLOCKED", "BLOCKED", "BLOCKED", "BLOCKED"},
{"UNRESERVED", "UNRESERVED", "RESERVED", "UNRESERVED"},
{"RESERVED", "RESERVED", "RESERVED", "RESERVED"}
},
1
)
And, when fetching the entity, everything works as expected:
Plane plane = entityManager.find(Plane.class, 1L);
assertEquals("ATR-42", plane.getName());
assertEquals(SeatStatus.BLOCKED, plane.getSeatStatus(1, 'A'));
assertEquals(SeatStatus.BLOCKED, plane.getSeatStatus(1, 'B'));
assertEquals(SeatStatus.BLOCKED, plane.getSeatStatus(1, 'C'));
assertEquals(SeatStatus.BLOCKED, plane.getSeatStatus(1, 'D'));
assertEquals(SeatStatus.UNRESERVED, plane.getSeatStatus(2, 'A'));
assertEquals(SeatStatus.UNRESERVED, plane.getSeatStatus(2, 'B'));
assertEquals(SeatStatus.RESERVED, plane.getSeatStatus(2, 'C'));
assertEquals(SeatStatus.UNRESERVED, plane.getSeatStatus(2, 'D'));