Data domain (kind of email model) :
- Message(id,subject,messageAttachment) OneToMany MessageAttachment(messageId,attachmentSHA1,message)
- Message(id,subject,messageAddress) OneToMany MessageAddress(messageId,email,type,message)
(@ManyToOne and OneToMany are bi-directionals)
My goal is to do :
SELECT
MessageAttachment.attachmentSHA1,
Message.subject,
MessageAddress.email
FROM MessageAttachment
JOIN FETCH Message {ON clause should be generated based on the domain}
JOIN FETCH MessageAttachment {ON clause should be generated based on the domain}
WHERE type='ReplyTo'
I want of course to avoid the N 1 problem (so I want just one select).
And I need the Criteria API to add dynamically specifications to the query.
So, something like that :
void go() {
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<MessageAttachment> query = criteriaBuilder.createQuery(MessageAttachment.class);
Root<MessageAttachment> root = query.from(MessageAttachment.class);
Fetch<Message, MessageAttachment> fetch = root.fetch("message").fetch("messageAddress");
//query.select(root).where(criteriaBuilder.equal(root.get("message").get("messageAddress").get("type"), "ReplyTo"));
List<MessageAttachment> l = em.createQuery(query).setMaxResults(2).getResultList();
System.err.println(l);
}
If I remove the comment, I get this Exception : Caused by: java.lang.IllegalStateException: Illegal attempt to dereference path source [null.message.messageAttachment] of basic type
CodePudding user response:
Try using this instead:
Join<Message, MessageAttachment> messageAddress = (Join<Message, MessageAttachment>) root.fetch("message").fetch("messageAddress");
query.select(root).where(criteriaBuilder.equal(messageAddress.get("type"), "ReplyTo"));
CodePudding user response:
Problem solved, thank you !
Remark, casting to (Join<Message, MessageAttachment>) didn't compiled, I needed to replaced it by (Join).
I still need have an unchecked cast warning, but I'm not sure it ispossible to avoid it.
Also, the X Y Z templates are a bit confusing.
Our code is : root.fetch("message").fetch("messageAddress");
Documentation says :
- @param the source type (As I understand, it is "Message")
- @param the target type (As I understand, it is "MessageAddress")
- public interface FetchParent<Z, X>
Method signature is : <X, Y> Fetch<X, Y> fetch(String attributeName);
So X becomes the source (Z) and Y the target(Z) ...
So shouldn't our code be like this ? Join<Message, MessageAddress> =(Join)root.fetch("message").fetch("messageAddress");
(Anyway, even Join<Object,Object> works as well).