I got a bit muddled while editing the code.
Standard 1:1 relationship in JPA is a foreignKeyRelationship in
EclipseLink, and a join is NOT required.
MappedBy relationship in JPA is a targetForeignKeyRelationship in
EclipseLink, and a join IS required.
DatabaseMapping mapping = ((SingularAttributeImpl)
attribute).getMapping();
if (mapping.isOneToOneRelationship() &&
!((OneToOneMapping)mapping).isForeignKeyRelationship()) {
cq.where(cb.isNull(root.join(First_second, JoinType.LEFT)
))
;
} else {
cq.where(cb.isNull(root.get(First_second)));
}
I haven't tested it, so it may need some work to compile.
Best Regards,
Chris
On 08/01/2016 12:59 PM, christopher
delahunt wrote:
Hello Mauro,
I misread your email and I guess my comment applies to the bug,
not your email. As stated, I don't believe the bug you filed is a
bug.
If you are attempting to avoid the out join for this one use case
that does not require it, I don't think anything in the JPA
interfaces will directly help, and this is a provider specific
optimization anyway that might not exist in other providers
anyway. You should not be accessing the mapping native api to
build your query, but to decide which way to build it. If the
OneToOneMapping underneath has isForeignKeyRelationship set to
true, then it owns the relationship and you can do the straight .
Otherwise it is what is referred to in native EclipseLink as a
targetForeignKey relationship, where the target descriptor
has/controls the foreign key, and you need to use a left outer
join.
So something like:
DatabaseMapping mapping = ((SingularAttributeImpl)
attribute).getMapping();
if (mapping.isOneToOneRelationships() &&
!((OneToOneMapping)mapping).isForeignKeyRelationship) {
cq.where(cb.isNull(root.get(First_second)));
} else {
cq.where(cb.isNull(root.join(First_second, JoinType.LEFT)
))
;
}
Hope this helps.
Best Regards,
Chris
On 08/01/2016 12:10 PM, Mauro
Molinari wrote:
Hi Chris,
thank you very much for your feedback.
Regarding the referenced bug, I understand your point of view
(the specification dictates a general attitude on the matter),
but the current behaviour is very counter-intuitive and brings
to wrong results as soon as I simply change the owner of the
one-to-one relationship. That is, a change in the mapping
(which should reasonably be transparent) breaks a query in the
object model, in which the intention to get "all the First
instances that do not have a corresponding Second instances"
is clear, rather than "give me always an empty result".
Anyway, the purpose of this message was not to bring that bug
(or enhancement or what you like) to the devs attention
(although that's good), but rather to request help to work
around it, i.e. to implement the outer join you also suggest.
When processing the metamodel in a completely generic way, if
I encounter the problematic case I need to get the foreign-key
attribute of the owning side of the relationship starting from
the non-owning side attribute (which is "mappedBy"). But I
still couldn't succeed on it, as I wrote in my previous e-mail
:-(
I'm now investigating on RelationshipAccessor class, but I've
yet to figure out how to get an instance of it...
Thanks again,
Mauro
Il 08/01/2016 17:44, christopher delahunt ha scritto:
Hello Mauro,
Frameworks don't automatically treat the join as a left out
join because traversing a path in JPA's criteria queries or
JPQL is supposed to be treated as an inner join. Section
4.4.4 of the JPA 2.1 specification requires that
"Path _expression_ navigability is composed using “inner join”
semantics. That is, if the value of a non-terminal field in
the path _expression_ is null, the path is considered to have no
value, and does not participate in the determination of the
result."
The fact that this works when the relationship is reversed is
a result of EclipseLink optimizations that take advantage of
the fact a join isn't required and not something intentionally
done for null handling. I believe I saw this behavior
difference documented when the feature was done, I just don't
have a link handy.
If you want consistent, spec compliant behavior in your
queries, you are required to specify the relationship use a
left join in the query. Ie:
"Select first from First first left join first.second second
where second is null"
or its equivalent in criteria expressions.
Best Regards,
Chris
One of the problems with considering this issue is that This
is why
On 08/01/2016 10:48 AM, Mauro
Molinari wrote:
Hello all,
I'm trying to implement some sort of "findByExample" feature
in my JPA application (using EclipseLink 2.6.1).
To do this, I'm inspecting the metamodel of my classes and
dynamically creating predicates to be added to a query built
with the Criteria API.
I encountered bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=485414
which is causing me a lot of headache.
To work around it, I'm trying to implement the following
logic: "if the attribute is mapping a bidirectional
relationship which is not owned by this entity, then do an
outer join and apply a condition on the corresponding
relationship attribute of the target entity".
The simple case would be:
Predicate predicate = cb.equal(from.get(attribute),
exampleValue);
which substantially is: "WHERE MyEntity.attribute =
<exampleValue>"
But if exampleValue is NULL and attribute is a
@OneToOne(mappedBy="inverseAttributeName"), so it's mapped
to a non-owned relationship, I have to do a different thing
to work around the aforementioned bug.
So, I have:
- attribute, which is a SingularAttribute
- attributeType, which is the attribute type (
attribute.getType() )
- if
attributeType.getPersistenceType() ==
PersistenceType.ENTITY (=> a relation
attribute) then I get:
DatabaseMapping mapping = ((SingularAttributeImpl)
attribute).getMapping();
The DatabaseMapping object is promising, because it has the
method getRelationshipPartnerAttributeName() (or even
getRelationshipPartner()) which, if I understand it
correctly, should give me the attribute name of the related
entity, if this is a bidirectional mapping.
However what I see while debugging is that both methods
always return null (also the protected field
"mapping.mappedBy" is null!!), even if attribute is a
SingularAttributeImpl of an attribute which is mapped like
this:
@OneToOne(cascade = CascadeType.ALL, fetch =
FetchType.LAZY, mappedBy = "inverseAttributeName",
optional = true, orphanRemoval = true)
and the inverse mapping is present (so the relationship
actually *is* bidirectional):
@Id @OneToOne(fetch = FetchType.EAGER, optional =
false)
Something similar seems to be the fields
mapping.targetToSourceKeyFields and
mapping.sourceToTargetKeyFields, but those are maps
containing DatabaseFields, not attributes, so I doubt I can
use them to build my query (unless, of course, I am lucky
and the attribute name matches the database column name).
On the other hand, I can't find anything else useful in
SingularAttributeImpl (not to say the plain JPA
interface...) to get the desired result.
I'm almost at it, but I already spent a lot of time on this
final detail without success :-(
Any help would be *really* appreciated.
Thanks in advance,
Mauro
_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/eclipselink-users
_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/eclipselink-users
_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/eclipselink-users
_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/eclipselink-users
|