eclipseLink multitenancy bug: tenant id not added - eclipselink

eclipseLink multitenancy bug: tenant id not added. I tried both 2.5.1 and 2.6.1.
For example,
Student and Course: ManyToMany.
Student Course Student_Course
------- ------------------ -----------------
id, name id, name, tenantId studentId, courseId
public class Student {
#ManyToMany(...)
List<Course> getCourses() {
...
}
}
Course is multitenancy enabled, but Student is not.
Search student left join course: The generated SQL:
SELECT DISTINCT t1.ID AS a1, t1.NAME AS a2, t1.VERSION AS a3, t0.ID AS a4,
t0.tenantId AS a5, t0.NAME AS a6, t0.VERSION AS a7 FROM Student t1 LEFT OUTER
JOIN (Student_Course t2 JOIN Course t0 ON (t0.ID = t2.courseId)) ON
(t2.studentId = t1.ID) ORDER BY t1.ID DESC
The restriction for Course.tenantId is not added into the query.
<entity class="Course" >
<multitenant>
<tenant-discriminator-column name="tenantId" context-property="tenant.id"
discriminator-type="INTEGER"/>
</multitenant>
</entity>
EntityManager em = ..
em.setProperty("tenant.id", 1);
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Student> criteriaQuery = criteriaBuilder.createQuery(Student.class);
Root<Student> root = criteriaQuery.from(Student.class);
root.fetch("courses", JoinType.LEFT);
criteriaQuery.distinct(true);
TypedQuery<Student> query = em.createQuery(criteriaQuery);
List<Student> students = query.getResultList();
The courses of a retrieved student will contain all the courses of the student from all tenants. But only the courses from tenant 1 is wanted.
Is there any workaround? Thanks.

It seems there was a bug
Bug 345962 - Join fetch query when using tenant discriminator column fails.
that has been solved in version 2.2.1 of javax.persistence which can be found on version 2.7.3 of org.eclipse.persistence
mvn javax.persistence

Related

Query for updating a column in same table from same table

I have to update the authorid column which are matching (where documentculture = 'en-US'
to matching (where documentculture = 'el-GR' in the same table. which includes a inner join to another table
I written like below which looks wrong:
UPDATE t1
SET t1.authorid = t2.authorid
FROM wv_blogdata AS t1
INNER JOIN wv_blogdata AS t2
ON t1.documentnodeid = t2.documentnodeid
inner join CMS_Document d
ON d.BlogDataID = d.DocumentForeignKeyValue
WHERE t2.DocumentCulture = 'en-US';
could you please correct me?
More explanation:
select authorid from wv_blogdata
inner join CMS_Document
on wv_blogdata.BlogDataID = CMS_Document.DocumentForeignKeyValue
Where DocumentCulture ='el-GR'
The author id of above query is different from authorid of below query
which i want to make it synch
select authorid from wv_blogdata
inner join CMS_Document
on wv_blogdata.BlogDataID = CMS_Document.DocumentForeignKeyValue
Where DocumentCulture ='en-US'
As Zohar Peled says in the comments, unless you give sample data, expected results as well as your current DML it's hard to produce an accurate answer to your question.
That being said, in general terms if you can produce a select statement using table aliases that shows both the field to be updated and the field with the new value then you can use it as the basis for a successful UPDATE query.
So if the correct results are shown in this query(your original converted into a SELECT):
SELECT t1.authorid AS OldValue, t2.authorid AS NewValue
FROM wv_blogdata AS t1
INNER JOIN wv_blogdata AS t2
ON t1.documentnodeid = t2.documentnodeid
INNER JOIN CMS_Document d
ON d.BlogDataID = d.DocumentForeignKeyValue
WHERE t2.DocumentCulture = 'en-US';
you will get the correct outcome from this query(your original):
UPDATE t1
SET t1.authorid = t2.authorid
FROM wv_blogdata AS t1
INNER JOIN wv_blogdata AS t2
ON t1.documentnodeid = t2.documentnodeid
INNER JOIN CMS_Document d
ON d.BlogDataID = d.DocumentForeignKeyValue
WHERE t2.DocumentCulture = 'en-US';
Remembering of course to test your work for unexpected outcomes and hidden gotchas.
Again without sufficient sample data it's really hard to give you a definitive answer, so include as much detail as possible to help us help you.
Hope this helps you to work it out.
The following query should make the records in sync so authorid of german blogs and authorid of usa blogs will become the same after you run this query.
Note that top(1) is required so only one value is returned by the sub-query else if there are multiple blog records for german culture you will encounter an error.
UPDATE b
SET b.authorid =
(SELECT top(1) wvb.authorid
FROM wv_blogdata wvb
INNER JOIN CMS_Document cms ON wvb.BlogDataID = cms.DocumentForeignKeyValue
WHERE cms.DocumentCulture ='el-GR' AND b.BlogDataID = cms.DocumentForeignKeyValue order by wvb.authorid)
FROM wv_blogdata b
INNER JOIN CMS_Document ON b.BlogDataID = CMS_Document.DocumentForeignKeyValue
WHERE CMS_Document.DocumentCulture ='en-US';

SQL Server Query for Mutual Matches in the same Table (2012)

We have a table with following columns in Tenants Table.
TenantID
Name
address
Current_Bedrooms
Bedrooms_Needed
Current_City
City_Needed
For a given row, how can we write a query that will find the match the bedrooms_Needed with Current_Bedrooms (same with city) in other rows
example
Select * from Tenants where Current_Bedrooms = Bedrooms_Needed and TenantID = 1234
It sounds like you want the tenants to 'swap' with eachother?
You can join the tenants table with itself (aliased as t1 and t2), while specifying the matching criteria as the join condition:
Select T1.Name As TenantFrom, t2.Name AS TenantTo
from Tenants t1
INNER JOIN Tenants t2
ON t1.Bedrooms_Needed = t2.Current_Bedrooms
AND t1.City_Needed = t2.Current_City
AND t1.TenantID <> t2.TenantID
WHERE t1.TenantID = 1234;
The tenant id exclusion is to prevent self-matches in the event of the tenant living in an exact match already.
Edit, Re Mutual Matches
In order to find pairs of mutually matching tenants, you will need to add the reciprocal criteria as additional filters:
Select T1.Name As TenantFrom, t2.Name AS TenantTo
from Tenants t1
INNER JOIN Tenants t2
ON t1.Bedrooms_Needed = t2.Current_Bedrooms
AND t1.City_Needed = t2.Current_City
AND t1.Current_Bedrooms = t2.Bedrooms_Needed
AND t1.Current_City = t2.City_Needed
AND t1.TenantID <> t2.TenantID
WHERE t1.TenantID = 1234;

Retrieve data from third table

This question is irritating to ask, as i haven't got the hang of using middle tables in sql yet. But i'm in a time rush so i've chosen to ask anyway.
I wish to combine these sql codes so i can retrieve the data from "teacher" aswell as "team" and "level", in the same repeater.
I'm catching a name from the "teacher" table through the FK_teacher from the middletable "teacher_team" which is related to my team table through FK_team
Would it by any chance be possible to combine these so i could extract it all through one repeater?
// Team <-> level relation
SELECT
team.team_id as team_id,
level.level as level,
FROM team
INNER JOIN level ON level.level_id = team.team_FK_level
WHERE team.team_FK_type = #id
// Team <-> Team_Teacher <-> Teacher relation
SELECT teacher.teacher_name as name
FROM teacher WHERE teacher.teacher_id
IN (
SELECT teacher_team.FK_teacher
FROM teacher_team
INNER JOIN team ON team.team_id = teacher_team.FK_team
WHERE team.team_FK_type = #id
)
* EDIT *
Got this code to work based on the answer of Ravi Singh. I've encountered another problem.
My repeater will output the teams row twice, if there are two teachers related to it in the teacher_teams (of course). Is there any way i could merge these without making a repeater inside a repeater?
SELECT
team.team_id as team_id,
level.level as level,
teacher_team.FK_teacher,
teacher.teacher_name as teacher
FROM team
INNER JOIN level ON level.level_id = team.team_FK_level
LEFT JOIN teacher_team on teacher_team.FK_hold = team.team_id
LEFT JOIN teacheron teacher.teacher_id = teacher_team.FK_teacher
WHERE team.team_FK_type = #id
Try this :
SELECT
teacher.teacher_name as name
,team.team_id as team_id
,level.level as level
FROM teacher
inner join teacher_team on teacher.teacher_id =teacher_team.FK_teacher
INNER JOIN team ON team.team_id = teacher_team.FK_team
INNER JOIN level ON level.level_id = team.team_FK_level
WHERE team.team_FK_type = #id
Update :
This should help with your updated question :
with demo_cte as(
SELECT
teacher.teacher_name as name
,team.team_id as team_id
,level.level as level
FROM teacher
inner join teacher_team on teacher.teacher_id =teacher_team.FK_teacher
INNER JOIN team ON team.team_id = teacher_team.FK_team
INNER JOIN level ON level.level_id = team.team_FK_level
WHERE team.team_FK_type = #id
)
select distinct t1.team_id,
t1.level,
STUFF(
(SELECT ', ' + t2.name
FROM demo_cte t2
where t1.team_id = t2.team_id
and t1.level = t2.level
FOR XML PATH (''))
, 1, 1, '') AS name
from demo_cte t1;

OJB ReportQuery join question

Given three tables:
People: {Person_Id, Age}
Accounts: {Account_Id, Person_Id, Account_Type}
Age_Ranges: {Age_Range_Id, Age_Range_Label, Lower_Bound, Upper_Bound}
I'm trying to represent the following SQL query using OJB (without resorting to a QueryBySQL):
select ar.Age_Range_Label, count(a.Account_Id)
from People p
inner join Accounts a on p.Person_Id = a.Person_Id
inner join Age_Ranges ar on p.Age between ar.Lower_bound and ar.Upper_Bound
where a.Account_Type = 'Chequing'
The java code I have so far looks like this:
Criteria criteria = new Criteria();
criteria.addEqualTo("Account_Type", "Chequing");
// join on Age_Ranges based on the person's Age
criteria.???
ReportQueryByCriteria q = QueryFactory.newReportQuery(Accounts.class, criteria);
q.setAttributes(new String[] {"Age_Range_Label", "count(Account_Id)"});
q.addGroupBy("Age_Range_Label");
...
But I'm unsure how to join up with the Age_Ranges table such that I can group on the Age_Range_Label column.
Any insight?

Selecting the first row out of many sql joins

Alright, so I'm putting together a path to select a revision of a particular novel:
SELECT Catalog.WbsId, Catalog.Revision, NovelRevision.Revision
FROM Catalog, BookInCatalog
INNER JOIN NovelMaster
INNER JOIN HasNovelRevision
INNER JOIN NovelRevision
ON HasNovelRevision.right = NovelRevision.obid
ON HasNovelRevision.Left=NovelMaster.obid
ON NovelMaster.obid = BookInCatalog.Right
WHERE Catalog.obid = BookInCatalog.Left;
This returns all revisions that are in the Novel Master for each Novel Master that is in the catalog.
The problem is, I only want the FIRST revision of each novel master in the catalog. How do I go about doing that? Oh, and btw: my flavor of sql is hobbled, as many others are, in that it does not support the LIMIT Function.
****UPDATE****
So using answer 1 as a guide I upgraded my query to this:
SELECT Catalog.wbsid
FROM Catalog, BookInCatalog, NovelVersion old, NovelMaster, HasNovelRevision
LEFT JOIN NovelVersion newRevs
ON old.revision < newRevs.revision AND HasNovelRevision.right = newRevs.obid
LEFT JOIN HasNovelRevision NewerHasNovelRevision
ON NewerHasNovelRevision.right = newRevs.obid
LEFT JOIN NovelMaster NewTecMst
ON NewerHasNovelRevision.left = NewTecMst.obid
WHERE Catalog.programName = 'E18' AND Catalog.obid = BookInCatalog.Left
AND BookInCatalog.right = NewTecMst.obid AND newRevs.obid = null
ORDER BY newRevs.documentname;
I get an error on the fourth line:
"old"."revision": invalid identifier
SOLUTION
Well, I had to go to another forum, but I got a working solution:
select nr1.title, nr1.revision
from novelrevision nr1
where nr1.revision in (select min(revision) from novelrevision nr2
where nr1.title = nr2.title)
So this solution uses the JOIN mentioned by the OA, along with the IN keyword to match it to a revision.
Something like this might work, it's called an exclusive left join:
....
INNER JOIN NovelRevision
ON HasNovelRevision.right = NovelRevision.obid
LEFT JOIN NovelRevision as NewerRevision
ON HasNovelRevision.right = NewerRevision.obid
AND NewerRevision.revision > NovelRevision.revision
...
WHERE NeverRevision.obid is null
The where clause filters out rows for which a newer revision exists. This effectively limits the query to the newest revisions.
In response to your comment, you could filter out only revisions that have a newer revision in the same NovelMaster. For example:
....
LEFT JOIN NovelRevision as NewerRevision
ON HasNovelRevision.right = NewerRevision.obid
AND NewerRevision.revision > NovelRevision.revision
LEFT JOIN HasNovelRevision as NewerHasNovelRevision
ON NewerHasNovelRevision.right = NewerRevision.obid
LEFT JOIN NovelMaster as NewerNovelMaster
ON NewerHasNovelRevision.left = NewerNovelMaster.obid
AND NewerNovelMaster.obid = NovelMaster.obid
....
WHERE NeverNovelMaster.obid is null
P.S. I don't think you can group JOINs and follow them with a group of ON conditions. An ON must directly follow its JOIN.
You can use CTE
Check this
WITH NovelRevesion_CTE(obid,RevisionDate)
AS
(
SELECT obid,MIN(RevisionDate) RevisionDate FROM NovelRevision Group by obid
)
SELECT Catalog.WbsId, Catalog.Revision, NovelRevision.Revision
FROM Catalog, BookInCatalog
INNER JOIN NovelMaster
INNER JOIN HasNovelRevision
INNER JOIN NovelRevesion
INNER JOIN NovelRevesion_CTE
ON HasNovelRevision.[right] = NovelRevision.obid
ON HasNovelRevision.[Left]=NovelMaster.obid
ON NovelMaster.obid = BookInCatalog.[Right]
ON NovelRevesion_CTE.obid = NovelRevesion.obid
WHERE Catalog.obid = BookInCatalog.[Left];
First it select the first revision written for each novel (assuming obid is novel foriegn key) by taking the smallest date and group them.
then add it as join in your query