JPA Criteria 2 embebbed JOINs and condition between them - sql

I'm gonna adapt my problem to a simple example. Lets say I have 2 entities: Employee and EmployeeCompany (the class that defines the relation of a Employee with a Company).
I need to retrieve the Employee entities that are associated with 2 EmployeeCompany entities, and these 2 EmployeeCompany entities must share the same value for a specific attribute (let's call this attribute "X"). EmployeeCompany entities have also embebbed identifiers, so the entities definition would look something like this:
Employee:
Long idEmployee;
List<EmployeeCompany> employeeCompanies;
EmployeeCompany:
// Embebbed ID
EmployeeCompanyId id;
Long X;
EmployeeCompanyId:
Long idEmployee;
Long idCompany;
This is what I'm currently doing to make the 2 JOINs with the EmployeeCompany tables starting from the Employee entity:
Root<T> root = criteria.from(Employee.class);
Join<Object, Object> joinFirstEmployeeCompanyId = root.join("employeeCompanies").join("id");
Predicate finalPredicate = builder.equal(joinFirstEmployeeCompanyId.get("idCompany"), idCompany1);
Join<Object, Object> joinSecondEmployeeCompanyId = root.join("employeeCompanies").join("id");
finalPredicate = builder.and(finalPredicate, builder.equal(joinSecondEmployeeCompanyId.get("idCompany"), idCompany2));
My problem is, I don't know how I can specify now that between these 2 joins, they must meet the X attribute condition (both EmployeeCompany entities must have the same value for the X attribute).
In case it helps, this is what the SQL query would look like:
SELECT * FROM Employee e
INNER JOIN EmployeeCompany ec1 ON ec1.idemployee = e.idemployee AND ec1.idcompany = :idCompany1
INNER JOIN EmployeeCompany ec2 ON ec2.idemployee = e.idemployee AND ec2.idcompany = :idCompany2
WHERE c1.X = c2.X

I solved my issue this way:
Root<T> root = criteria.from(Employee.class);
Join<Object, Object> joinFirstEmployeeCompany = root.join("employeeCompanies");
joinFirstEmployeeCompany.on(builder.equal(joinFirstEmployeeCompany.get("id").get("idCompany"), idCompany1));
Join<Object, Object> joinSecondEmployeeCompany = root.join("employeeCompanies");
joinSecondEmployeeCompany.on(builder.equal(joinSecondEmployeeCompany.get("id").get("idCompany"), idCompany2));
Predicate finalPredicate = builder.equal(joinFirstEmployeeCompany.get("X"), joinSecondEmployeeCompany.get("X"));

Related

Select Related With Multiple Conditions

Using the Django ORM is it possible to perform a select_related (left join) with conditions additional to the default table1.id = table2.fk
Using the example models:
class Author(models.Model):
name = models.TextField()
age = models.IntegerField()
class Book(models.Model):
title = models.TextField()
and the raw sql
SELECT 'Book'.*, 'Author'.'name'
FROM 'Book'
LEFT JOIN
'Author'
ON 'Author'.'id' = 'Book'.'author_id'
AND 'Author'.'age' > 18 ;<---this line here is what id like to use via the ORM
I understand that in this simple example you can perform the filtering after the join, but that hasn't worked in my specific case. As i am doing sums across multiple left joins that require filters.
# gets all books which has author with age higher than 18
books = Book.objects.filter(author__age__gt=18)
returns queryset.
Then you can loop trough the queryset to access specific values and print them:
for b in books:
print(b.title, b.author.name, b.author.age)

Query with two reverse relationships in Django

If I have these Django models:
class ModelA(Model):
pass
class ModelB(Model):
a = ForeignKey(ModelA, ...)
d = ForeignKey(ModelD, ...)
r = IntegerField()
q = IntegerField()
class ModelC(Model):
a = ForeignKey(ModelA, ...)
d = ForeignKey(ModelD, ...)
r = IntegerField()
class ModelD(Model):
pass
How can I do a Django ORM query equivalent to this:
select ModelB.q, ModelA.id, ModelD.id
from ModelA
join ModelB on ModelB.a_id=ModelA.id
left join ModelC on (ModelC.a_id=ModelB.a_id and ModelC.r=ModelB.r
and ModelC.d_id=ModelB.d_id)
join ModelD on ModelB.d_id=ModelD.id
where ModelC.id is null
I.e. get ModelBs whose fields don't match any ModelCs, where both ModelB and ModelC have foreign keys to two other models.

MyBatis Insert a complex object which has associations

Hi Guys i have a complex object as below and would like to know how to write mapper.xml for the same.
I have knowledge to insert a simple object, but i am not getting this with 2 levels of Hierarchy.
Below is my domain object
class Org{
id=O1
str1;
List<Division>
}
class Divison{
id = D1
org = O1
str2;
List<Employees>
List<Managers>
}
class Employees{
str3;
id = E1
divId = D1
}
class Managers{
str3;
id = M1
divId = D1
}
So Org has multiple Divisons, Each Divison has multiple Employees and Managers.
How can i write my mybatis mapper.xml so that i can insert Organization, Divison, Employees and Managers to respective tables in one transaction

Count one-to-one relationship in grails

I have a problem doing a query. That I want to do is access with a query to the data in my "String code" in MyDomainA through a query from MyDomainB. The relationship between the tables is unidirectional one to one.
Is possible use a gorm way to do this??
Domain A:
class LicenceType {
String code
String description
Double price
static constraints = {
}
}
TABLE DOMAIN A
code description
A this is A
B this is B
C this is C
Domain B: (have the unidirectional relationship)
class VoiceUser {
LicenceType licenceType
String username
String email
String nameID
}
TABLE DOMAIN B
User
1
2
3
4
That I want to do is know how many users have the same code(code is a column of DomainA and both tables have a unidirectional relationship as I indicated before).
This is that I'm trying to do that is wrong...
Controller:
def resulta = VoiceUser.executeQuery('SELECT a.code, COUNT(b.nameID) FROM VoiceUser AS b INNER JOIN b.licenceType AS a GROUP BY a.code')
def resultCount = resulta[0]
This is some example result that I hope...
Users with code A = 2
Users with code B = 2
Users with code C = o
The trick is to do a group by on the code and a count() on the user. You can do this using either HQL or a criteria query.
HQL
Here's an example in HQL:
VoiceUser.executeQuery('SELECT licence.code, COUNT(user) FROM VoiceUser AS user INNER JOIN user.licenceType AS licence GROUP BY licence.code')
If you're familiar with SQL, most of this should make sense right away. An important difference is the syntax for joining domain classes. HQL deals with domain classes, not tables.
Criteria query
And here's the equivalent criteria query.
VoiceUser.withCriteria {
projections {
licenceType {
groupProperty('code')
}
count('id')
}
}
Alternative queries
The queries shown above return a List<List> like this:
[
['A', 2],
['B', 2],
['C', 0]
]
If you provide a LicenceType (or its code) as input to the query, then you can get the count for just that LicenceType. For instance, here are examples which retrieve the user count for licence code 'A'.
HQL
def result = VoiceUser.executeQuery('SELECT COUNT(user) FROM VoiceUser AS user INNER JOIN user.licenceType AS licence WHERE licence.code = :code', [code: 'A'])[0]
Criteria query
def result = VoiceUser.createCriteria().get {
licenceType {
eq('code', 'A')
}
projections {
count('id')
}
}
Additional resources
I've got a series of articles which explain HQL, criteria, and where queries in detail; such as how to use projections and joins. Feel free to check them out.

Django LEFT OUTER JOIN on TWO columns where one isn't a foreign key

I have two models like so:
class ObjectLock(models.Model):
partner = models.ForeignKey(Partner)
object_id = models.CharField(max_length=100)
class Meta:
unique_together = (('partner', 'object_id'),)
class ObjectImportQueue(models.Model):
partner = models.ForeignKey(Partner)
object_id = models.CharField(max_length=100)
... # other fields
created = models.DateTimeField(auto_now_add = True)
modified = models.DateTimeField(auto_now = True, db_index=True)
class Meta:
ordering = ('modified', 'created')
There is nothing notable about the third model mentioned above (Partner).
I'd like to get something like:
SELECT * FROM ObjectImportQueue q LEFT OUTER JOIN ObjectLock l ON
q.partner_id=l.partner_id AND q.object_id=l.object_id WHERE l.object_id
IS NULL and l.partner_id IS NULL;
I came across this page that tells how to do custom joins, and I tried passing in a tuple of the column names to join in place of the column name to join, and that didn't work. The Partner table shouldn't need to be included in the resulting sql query but I will accept an answer that does include it as long as it effectively does what I'm trying to do with one query.
If you're using Django 1.2+ and know the SQL you want, you could always fall back to a Raw Query.
I also meet a similar question.but finally,I found I asked a wrong question to be solve.
in the Django ORM,the condition of SQL join is base on what the models.Model fields defined.
there are Many-to-one relationships (ForeignKey),Many-to-many relationships(ManyToManyField),One-to-one relationships(OneToOneField).
in your situation.ObjectLockModel and ObjectImportQueueModel have the same part of fields, the partnerfield and object_idfield.yon should use One-to-one relationships.
you can change your Model like this:
class ObjectImportQueue(models.Model):
partner = models.ForeignKey(Partner)
object_id = models.CharField(max_length=100)
created = models.DateTimeField(auto_now_add = True)
modified = models.DateTimeField(auto_now = True, db_index=True)
def __unicode__(self):
return u"%s:%s" % (self.partner, self.object_id)
class Meta:
ordering = ('modified', 'created')
class ObjectLock(models.Model):
lock = models.OneToOneField(ObjectImportQueue, null=True)
class Meta:
unique_together = (('lock',),)
order of Model is import,OneToOneField argument model must come first.
>>> p1 = Partner.objects.get(pk=1)
>>> p2 = Partner.objects.get(pk=2)
>>> Q1 = ObjectImportQueue.objects.create(partner=p1,object_id='id_Q1')
>>> Q2 = ObjectImportQueue.objects.create(partner=p2,object_id='id_Q2')
>>> ObjectImportQueue.objects.filter(lock__isnull=True)
[<ObjectImportQueue: Partner object:id_Q1>, <ObjectImportQueue: Partner object:id_Q2>]
>>> L1 = ObjectLock.objects.create(lock=Q1)
>>> ObjectImportQueue.objects.filter(lock__isnull=True)
[<ObjectImportQueue: Partner object:id_Q2>]
ObjectLock.objects.createlock a object
ObjectImportQueue.objects.filter(lock__isnull=True) select object don't be lock.
if you use the appropriate relationships, generate the ORM query will be easy.In Django,Define the relationships during you build the Model is better than use Query statement to relation the relationships between tables.
I just found a solution to this problem.
You have to create a view that does the join for you
CREATE VIEW ImporQueueLock AS (
SELECT q.id, l.id
FROM ObjectImportQueue q
LEFT OUTER JOIN ObjectLock l
ON q.partner_id=l.partner_id AND q.object_id=l.object_id
)
Then make a django model for that view
class ImportQueueLock(models.Model):
queue = models.ForeignKey(ObjectImportQueue, db_column='q')
lock = models.ForeignKey(ObjectLock, db_column='l')
Then make a ManyToMany on your Django model from ObjectLock to ObjectImportQueue through ImportQueueLock
class ObjectLock(models.Model):
partner = models.ForeignKey(Partner)
object_id = models.CharField(max_length=100)
queue = models.ManyToManyField(ObjectImportQueue, through = ImportQueueLock)
and you will be able to do
ObjectLock.objects.filter(importqueuelock__objectimportqueue__ .....)