Can somebody help how to compose a HQL query with JPA #Query on the following line?
"get me all books which has this author and are published after year X"
Consider a simple entity without relationship - more concern on the JPA #Query and HQL combination:
#Entity
public class Book{
#Id
public int id;
public String title,
public String authorName;
public String yearOfPublish;
.....
}
The query would be:
select b from Book b where b.authorName = :authorName and yearOfPublish > :year
And as you are using Spring Data JPA you don't even need to write the Query! Simply write a method:
List<Book> findAllByAuthorNameAndYearOfPublishGreaterThan(String authorName, String yearOfPublish);
This will create the query for you.
Read for about Query methods in the official documentation: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods
Related
I want to select columns based on my input (List < String >)
#Entity
#Table
public class Product {
#Id
private Long id;
private String name;
private String price;
}
I understand that to select distinct specific columns, I can use #Query("SELECT DISTINCT name FROM TABLE")
However, I want to give users the flexibility to select the columns they want. e.g. List < String > columns = Arrays.asList(["name", "price"]). This will then select distinct from both name and price columns.
For this create a custom method implementation and use one of the following (or of the many variants thereof)
construct a SQL or JPQL query using String concatenation (be careful not to introduce SQL injection vulnerabilities).
use some kind of criteria API like
JPA Criteria API
Querydsl
JOOQ
In MongoDB, I can use $or[{key1:'value11', key2:'value12'}, {key1:'value21', key2:'value22'}, {key1:'value31', key2:'value32'}, ...] to query several documents which matches at least one of the expressions in the $or operator. Then how the thing can be done using Spring Data Reactive MonogoDB?
In particular, I define a entity class as:
#Document
public class MyDocument
{
#Id
private String id;
private String field1;
private String field2;
}
And then, the repository interface for the entity:
public interface MyDocumentRepository extends ReactiveMongoRepository<MyDocument, String>
The question now is how to define a method in MyDocumentRepository to query the documents with field1 and field2:
There seems no proper keywords to create a query method (findAllBy(field1AndField2)In???)
If using JSON-based Query Methods, I really do know how to complete the Cloze test...
#Query("{$or:[(:fields)]}
Flux<MyDocument> findAllBy????(Flux<???> fields)
Spring Data MongoDB has support for ReactiveMongoTemplate. In a repository, you can use this as a connection to MongoDB which can be used with #Autowire.
In ReactiveMongoTemplate you can create Criteria with and and or operation like
Query query = new Query();
query.addCriteria(
new Criteria().andOperator(
Criteria.where("field1").exists(true),
Criteria.where("field1").ne(false)
)
);
and this can be passed to MongoDB with the before created instance of ReactiveMongoTemplate
Flux<Foo> result = reactiveMongoTemplate.find(query, Foo.class);
Documentation for use of configuration of ReactiveMongoTemplate if needed can be found here
This HQL query give me error:
String q4 = "SELECT i, COUNT(ie) FROM CorsoStudi cs \n"
+ "\t JOIN cs.inserogati ie JOIN ie.insegn i \n"
+ "\t WHERE cs.nome = 'Laurea in Informatica' \n"
+ "\t GROUP BY i";
The error is:
Exception in thread "main" java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: insegn. of: component[_id,annierogazione,annoaccademico,crediti,discriminante,discriminantemodulo,hamoduli,id_facolta,insegn,inserogato_padre,modulo,nomemodulo,nomeunita,programma]
This is InsErogato:
#Embeddable
public class InsErogato {
private Integer _id;
private String annoaccademico;
#Embedded
private Insegn insegn;
#Embedded
private Discriminante discriminante;
private Integer modulo;
private String discriminantemodulo;
private String nomemodulo;
private Double crediti;
private String programma;
private Integer id_facolta;
private String hamoduli;
#Embedded
private InsErogatoPadre inserogato_padre;
private String nomeunita;
private Integer annierogazione;
// constructors, getters and setters and toString
}
and this is Insegn:
#Embeddable
public class Insegn {
private Integer _id;
private String nomeins;
private String codiceins;
// constructors, getters and setters and toString
}
Main:
// begin transaction
entityManager.getTransaction().begin();
List<Object[]> insegn = entityManager
.createQuery(q4, Object[].class)
.getResultList();
for(Object[] i : insegn) {
Insegn ins = (Insegn)i[0];
Long count = (Long)i[1];
System.out.println("nomeins: " + ins.getNomeins() + ", numero inserogati: " + count);
}
// commit transaction
entityManager.getTransaction().commit();
The MongoDB structure:
https://i.stack.imgur.com/qFusC.jpg
https://i.stack.imgur.com/k04HK.png
https://i.stack.imgur.com/H8nhS.png
https://i.stack.imgur.com/eYl2M.png
I tried to change the query but Hibernate doesn't find "insegn" (and also "discriminante") property in "inserogato", but he can find other simple attributes from it (like "annoaccademico" etc.).
The same query works on Hibernate ORM with PostgreSQL.
Maybe I have to add something in the annotations, or change the mongoDB structure (?).
I'm using Hibernate OGM 5.3.1.Final and MongoDB 3.6.3 JDBC Driver.
The same query works on Hibernate ORM with PostgreSQL
But PostgreSQL is a SQL database, MongoDB is a NoSQL database. Hibernate OGM is a means to add Hibernate ORM to NoSQL databases. The '(H)SQL' for OGM is limited (see below).
You don't say what your application is deployed on. I use WildFly 12.0.0.Final. I've had OGM with MongoDB working on version 11 & 12.
entityManager.getTransaction().begin();
I use the (WildFly) container to handle transactions. Annotate my EJB.
#TransactionManagement(TransactionManagementType.CONTAINER)
I don't believe you can use (H)SQL per se with Hiberate OGM but:
Use JPQL - only for simple queries for now
Use the NoSQL native query mapping the result as managed entities
Use Hibernate Search queries - primarily full-text queries
It says in the documentation:
In particular and of notice, what is not supported is:
cross entity joins
JPQL functions in particular aggregation functions like count
JPQL update and delete queries
One of my queries:
Query query = mongoDBEntityManager.createQuery("FROM FoodsCosmeticsMedicines f WHERE f.ean = :ean")
.setParameter("ean", ean);
The entity (the #Expose are for the JSON)
#Entity(name = "FoodsCosmeticsMedicines")
#Indexed
#Table(name = "foodsCosmeticsMedicines")
public class FoodsCosmeticsMedicines implements Serializable {
// Arrays of Objects
#Expose(deserialize = true, serialize = true)
#Embedded
ProductCharacteristics productCharacteristics;
#Expose(deserialize = true, serialize = true)
#Embedded
CalcNutrition calcNutrition;
#Expose(deserialize = true, serialize = true)
#Embedded
Nutrients nutrients;
#Expose(deserialize = true, serialize = true)
#Embedded
Enumbers enumbers;
#Expose(deserialize = true, serialize = true)
#Embedded
ChemicalsMineralsVitamins chemicalsMineralsVitamins;
#Expose(deserialize = true, serialize = true)
#Embedded
Lifestyle lifestyle;
.....
}
Why are you using JOIN?
With MySQL I use Hibernate as my ORM I would use annotations to map relationships with entities such as:
#OneToOne(cascade = CascadeType.ALL, mappedBy = "product", fetch = FetchType.LAZY)
private UriEntity uri;
entityManager.getTransaction().commit();
This is irrelevant as all you've done is read. Maybe you excluded the persist?
I'm sure you've read the documentation. I found all the answers to the problems I encountered here:
Hibernate OGM 5.3.1.Final: Reference Guide
Currently, queries with group by are not supported. You will need to run a native MongoDB query for this particular use case. See the reference documentation for more details about it.
I think the join on an embedded entity instead of a collection is confusing the parser even if it's a valid query. You should see a clearer exception with the following one (equivalent to the one you are trying):
SELECT ie.i, COUNT(ie)
FROM CorsoStudi cs
JOIN cs.inserogati ie
WHERE cs.nome = 'Laurea in Informatica'
GROUP BY ie.i;
It should throw:
java.lang.UnsupportedOperationException: The GROUP BY clause is not supported
Aggregate functions are not supported as well.
I am trying to use nested Mongodb query but it does not work.
It is similar to Spring data mongodb query for subdocument field
But suggestions mentioned there does not work.
Please find my documents below.
#Document
public class Ticket {
#Id
private String id;
#DBRef
#CascadeSave
private Customer customer;
// getters and setters
}
#Document
public class Customer {
#Id
private String id;
private String firstName;
// getters and setters
}
public interface TicketRepository extends MongoRepository<Ticket, String> {
public List<Ticket> findByCustomerFirstName(String firstName);
}
I tried both findByCustomerFirstName and findByCustomer_FirstName but it does not work. Any suggestions ?
These suggestions are right it should work...
Official docs explains it as you did it:http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#repositories.query-methods.query-property-expressions
Property expressions can refer only to a direct property of the
managed entity, as shown in the preceding example. At query creation
time you already make sure that the parsed property is a property of
the managed domain class. However, you can also define constraints by
traversing nested properties. Assume a Person has an Address with a
ZipCode. In that case a method name of
List<Person> findByAddressZipCode(ZipCode zipCode);
creates the
property traversal x.address.zipCode
Just one thing, remove #Document from Customer and try it, Mongodb didn't support join queries (I'm not sure if now it does)... so you're document should be Ticket and it must have a embbebed document Customer as a inner object and not in a different document.
Say I have a User class which has a manual reference to a customer document:
public class User(){
#Id
public String id;
public String name;
public String customerId;
}
I want both the id & customerId to be stored as an ObjectId in mongo.
When saving a User document, the "id" gets converted to an ObjectId, however, the customerId gets saved as a string. I could have customerId of type ObjectId, but I would rather have the POJO as a string and have the customerId automatically convert to ObjectId when saving/querying. There does not seem to be any built in annotation which behaves like #Id, but can be used for manual references. How would I go about creating one, or is there a better solution? I have read a bit above converters, but I do not want to re-map the whole POJO to a DBObject.
Any advice would be appreciated.
when you get your customer data you have to create the objectId yourself.
Db.Customer.find({"_id" : new ObjectId("$valueFromUserTable")});
so in Spring Java you would:
ObjectId objId = new ObjectId("$valueFromUserTable");
Query query = new Query(Criteria.where("_id").is(objId));
Customer customer = super.mongoOps.find(query, Customer.class);