How do I traverse a relationship in a WHERE clause with OpenJPA? - jpa

I am new to JPA and OpennJPA. I have two entities UserDmo and SupplierDmo. Each Supplier can have several users and this relationship is established as follws,
In UserDmo,
Column(name="id_supplier")
private long idSupplier;
#ManyToOne(optional=true)
#JoinColumn(name="ID_SUPPLIER")
private SupplierDmo supplier;
In here column ID_SUPPLIER is the FK with referenced by ID column of the SupplierDmo. Using these two entities I tried to obtain result by following query.
SELECT u.id, u.modifiedDate FROM UserDmo u JOIN u.idSupplier s WHERE s.id = 1
But I got, Error message: Attempt to query field "s.id" from non-entity variable "s". Perhaps you forgot to prefix the path in question with an identification variable from your FROM clause?
I really appreciate your help on this

Try something like this :
SELECT u.id, u.modifiedDate FROM UserDmo u WHERE u.supplier.id = 1

Related

Linq GroupJoin (join...into) results in INNER JOIN?

I am referencing the accepted answer to this question:
LINQ to SQL multiple tables left outer join
In my example, I need all of the Person records regardless if there is a matching Staff record.
I am using the following query (simplified for illustation's sake):
var result = from person in context.Person
join staffQ in context.Staff
on person.StaffID equals staffQ.ID into staffStaffIDGroup
from staff in staffStaffIDGroup.DefaultIfEmpty()
select new PersonModel()
{
ID = person.ID,
Fname = person.Fname,
Lname = person.Lname,
Sex = person.Sex,
Username = staff != null ? staff.Username : ""
};
However, contrary to my expectations, the query results in the following SQL with an INNER JOIN, which eliminates records I need in the the result set.
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[fname] AS [fname],
[Extent1].[lname] AS [lname],
[Extent1].[sex] AS [sex],
[Extent2].[username] AS [username]
FROM [dbo].[Person] AS [Extent1]
INNER JOIN [dbo].[Staff] AS [Extent2] ON [Extent1].[StaffID] = [Extent2].[ID]
I thought that GroupJoin (or join...into) is supposed to get around this? I know I must have made a dumb mistake here, but I can't see it.
In general the query should generate left outer join.
But remember, this is EF, and it has additional information coming from the model. In this case looks like the StaffID property of Person is an enforced FK constraint to Stuff, so EF knows that there is always a corresponding record in Staff table, hence ignoring your left outer join construct and generates inner join instead.
Again, the model (properties, whether they are required or not, the relationships - required or not etc.) allows EF to perform similar smart decisons and optimizations.
Use a Navigation Property instead of a Join. If you're using a Join in EF LINQ you're almost always doing the wrong thing.
Something like
var result = from person in context.Person
select new PersonModel()
{
ID = person.ID,
Fname = person.Fname,
Lname = person.Lname,
Sex = person.Sex,
Username = person.StaffId != null ? Person.Staff.Username : ""
};

JPA: Querying an object and single values from other entity

Is it possible with JPA to query a database to get an entity filled with an additional field belonging to another table/entity?
I have a reservations table holding a foreign key to a record(an entity) in another table pois which has to columns of interest: poiId and poiType.
Instead of having a field ReservationEntity.poi (to finally obtain poi.poiType) I want to have a ReservationEntity.poiId and ReservationEntity.poiType and I wonder if it's possible to achieve this through a NamedQuery:
#NamedQuery(name="ReservationEntity.findByRfId", query="SELECT r, p.poiType FROM ReservationEntity r LEFT JOIN PoiEntity p ON r.poiId = p.poiId WHERE r.rfId = :rfId")
...since you read my question you can imagine that this DOESN'T work. ;-)
Is it possible to do it in such a kind?
Here's the exception:
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'POITYPE' in 'field list'
Error Code: 1054
Call: SELECT reservationId, endTime, notification, poiId, POITYPE, startTime, status, timeZone, tstamp, type FROM reservations WHERE (reservationId = ?)
bind => [1 parameter bound]
Query: ReadObjectQuery(name="ReservationEntity.findById" referenceClass=ReservationEntity sql="SELECT t1.reservationId, t1.authInfo, t1.endTime, t1.evsp, t1.notification, t1.poiId, t1.POITYPE, t1.startTime, t1.status, t1.timeZone, t1.tstamp, t1.type FROM reservations t1 LEFT OUTER JOIN pois t0 ON (t1.poiId = t0.poiId) WHERE (t1.reservationId = ?)")
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340)
By now I made it work using a database view instead of a table for the #Entity(...) annotation.
Yet I don't have the requirement to update the entity. However, it is possible to update a view as long as only one table' column are modified and an INNER JOIN is used: http://dev.mysql.com/doc/refman/5.6/en/view-updatability.html

Entity Framework 5: How to Outer Join Table Valued Function

I'm attempting to outer join a table with an inline table valued function in my LINQ query, but I get a query compilation error at runtime:
"The query attempted to call 'OuterApply' over a nested query, but 'OuterApply' did not have the appropriate keys."
My linq statement looks like this:
var testQuery = (from accountBase in ViewContext.AccountBases
join advisorConcatRaw in ViewContext.UFN_AccountAdvisorsConcatenated_Get()
on accountBase.AccountId equals advisorConcatRaw.AccountId into advisorConcatOuter
from advisorConcat in advisorConcatOuter.DefaultIfEmpty()
select new
{
accountBase.AccountId,
advisorConcat.Advisors
}).ToList();
The function definition is as follows:
CREATE FUNCTION dbo.UFN_AccountAdvisorsConcatenated_Get()
RETURNS TABLE
AS
RETURN
SELECT AP.AccountId,
LEFT(AP.Advisors, LEN(AP.Advisors) - 1) AS Advisors
FROM ( SELECT DISTINCT
AP.AccountId,
( SELECT AP2.PropertyValue + ', '
FROM dbo.AccountProperty AP2 WITH (NOLOCK)
WHERE AP2.AccountId = AP.AccountId
AND AP2.AccountPropertyTypeId = 1 -- Advisor
FOR XML PATH('')) AS Advisors
FROM dbo.AccountProperty AP WITH (NOLOCK)) AP;
I can successfully perform the join directly in sql as follows:
SELECT ab.accountid,
advisorConcat.Advisors
FROM accountbase ab
LEFT OUTER JOIN dbo.Ufn_accountadvisorsconcatenated_get() advisorConcat
ON ab.accountid = advisorConcat.accountid
Does anyone have a working example of left outer joining an inline TVF to a table in LINQ to entities - or is this a known defect, etc? Many thanks.
Entity Framework needs to know what the primary key columns of the TVF results are to do a left join. Basically you need to create a fake table which has same schema as your TVF results and update TVF in model browser to return the new created table type instead of default complex type. You could refer to this answer to get more details.

In JPA 2.0 JPQL, when one returns a NEW object, how may one make use of FETCH JOINs?

A colleague of mine has the following (apparently invalid) JPQL query:
SELECT NEW com.foobar.jpa.DonationAllocationDTOEntity(a.id, a.campaign, a.campAppeal, a.campDivision, a.divisionFund)
FROM DonationAllocation a JOIN a.donation d JOIN a.allocationType t
JOIN FETCH a.campaign
WHERE d.id = :donationId
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge')
It is worth noting (for later in this message) that DonationAllocation's relationship with a Campaign entity is many-to-one, and is marked as FetchType.LAZY. My colleague's intent with this query is to (among other things) ensure that a.campaign is "inflated" (eagerly fetched).
Hibernate (obviously just one JPA implementation of several), when faced with this query, says:
query specified join fetching, but the owner of the fetched association was not present in the select list
This makes sense, as the select list contains only NEW DonationAllocationDTOEntity(), and section 4.4.5.3 of the JPA 2.0 specification says:
The association referenced by the right side of the FETCH JOIN clause must be an association or element collection that is referenced from an entity or embeddable that is returned as a result of the query.
So since there is no "entity or embeddable that is returned as a result of the query" (it's a DTO constructed using the NEW operator), it follows that there is no possible association for a FETCH JOIN to reference, and hence this query is invalid.
How, given this limitation, should one construct a JPQL query in this case such that a.campaign--passed into the constructor expression--is fetched eagerly?
I would simply select the entity and its association, and llopover the results to invoke the DTO constructor explicitely. You would have the additional advantage of compile-time checks and refactorable code:
select a from DonationAllocation a
JOIN a.donation d
JOIN a.allocationType t
JOIN FETCH a.campaign
WHERE d.id = :donationId
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge')
...
for (DonationAllocation a : list) {
result.add(new DonationAllocationDTOEntity(a.id,
a.campaign,
a.campAppeal,
a.campDivision,
a.divisionFund));
}
EDIT:
This query should also select what's needed, and avoid selecting the whole DonationAllocation entity:
select a.id, a.campaign, a.campAppeal, a.campDivision, a.divisionFund
from DonationAllocation a
JOIN a.donation d
JOIN a.allocationType t
WHERE d.id = :donationId
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge')
and you might just add the DTO constructor in the query if you want:
select new com.foobar.jpa.DonationAllocationDTOEntity(a.id, a.campaign, a.campAppeal, a.campDivision, a.divisionFund)
from DonationAllocation a
JOIN a.donation d
JOIN a.allocationType t
WHERE d.id = :donationId
AND (t.code = 'Pledge' OR t.code = 'MatchingPledge')
The fact the a.campaign is in the select clause should be sufficient to tell Hibernate to load the entity. At least that's how it behaves in my tests.

Why does JPQL's "OR" operator narrow result set?

I have three tables: "User", "Employee" and "Worker". "User" table has one-to-zero-or-one relationship with "Worker" and the same one-to-zero-or-one with "Employee". User entity bean has following mapping attributes:
#OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
private Worker worker;
#JoinColumn(name = "id_employee", referencedColumnName = "id")
#OneToOne
private Employee idEmployee;
My aim is to get all "User" records which have one of this attributes filled (not null). I try to use the query:
SELECT u FROM User u WHERE u.idEmployee IS NOT NULL OR u.worker IS NOT NULL
ORDER BY u.login
I suppose to get 15 records, but I get only 6. I divided this query into two separate:
SELECT u FROM User u WHERE u.idEmployee IS NOT NULL ORDER BY u.login;
SELECT u FROM User u WHERE u.worker IS NOT NULL ORDER BY u.login;
I get 9 and 6 records, respectively. Put together - required 15 records.
It looks like "OR" narrows the result set to only those records, which have worker field not null. Why does it work in such way? Thanks in advance.
The worker association is mapped by a foreign key in the worker table. This means that using u.worker makes an inner join to the worker table, and the is not null is always true. The resulting SQL should look like this:
select u.* from user u, worker w where u.id = w.user_id and w.user_id is not null.
You need to use a left join to accept users having no worker:
select u from User u
left join u.worker w
left join u.employee e
where w is not null or e is not null
i actually had similar problem recently, and it turns out i was using old version of eclipse link, where statements is null and is not null wasn't correctly executed if they were part of and/or statement.
If i remember fix for that was in eclipse link 2.2.0. if you are not using eclipse link, ignore my post.