Does JPA criteria api have a problem with JOIN and IN? - sql

This is a JPA Query question. I have successfully used "LEFT JOIN" and "IN:" in EntityManager.CreateQuery in separate situations, but when i combine the two e.g.
SELECT a.id
FROM TableA a
LEFT JOIN TableB b on a.myAField = b.id and b.myBField in :Ids
LEFT JOIN TableC c on b.myBOtherField = c.id
where Ids is List<Long> it starts giving me this error "The left parenthesis is missing from the IN expression."
The sql works fine when pasted directly into postGres pgAdmin explicitly writing out the parameters. Have I made a mistake with the syntax here or is this a jpa limitation and i need an alternative?
List<Long> myBFieldTypes = new ArrayList<>();
myBFieldTypes.add(5L);
myBFieldTypes.add(10L);
try {
List<Long> resultArray = em.createQuery("SELECT a.id FROM TableA a LEFT JOIN TableB b on a.myAField = b.id and b.myBField in :Ids LEFT JOIN TableC c on b.myBOtherField = c.id")
.setParameter("Ids", myBFieldTypes)
.getResultList();
return resultArray;
} catch (Exception ex) {
throw ex;
} finally {
em.close();
}

Related

Joining multiple tables using JPA #SecondaryTables

I need to join 3 tables where A.id == B.id and B.id == C.id using JPA #SecondaryTables where I need to map these tables to a single entity. what is the way I should I should try?
Since A.ID = B.ID = C.ID, you can just have 2 secondary tables, with the relationship A.ID = B.ID, and A.ID = C.ID. Your "main" table will be A, and B and C are your secondary tables. You can reference the table as follows in your column declaration. (many other parameters in the annotations left out for brevity)
#Entity
#Table(name = "A")
#SecondaryTables({
#SecondaryTable(name="B", #PrimaryKeyJoinColumn(name="ID", referencedColumnName="ID")),
#SecondaryTable(name="C", #PrimaryKeyJoinColumn(name="ID", referencedColumnName="ID"))
})
public Claass Blah {
#ID
private int id;
#Column(table = "B")
private String someColumn;
#Column(table = "C")
private String someOtherColumn;
etc...
}

Linq to SQL include related table

Been trying for a while now, but just can't get it to work the way I want. Referring to the code snippet below, I want to include a related table to Bricks (BrickColors). As of now BrickColors are not included and is lazy loaded.
var query = (from ul in DbContext.UserLocs
join l in DbContext.Locs on ul.LocId equals l.Id
join lb in DbContext.LocBricks on l.Id equals lb.LocId
join b in DbContext.Bricks on lb.BrickId equals b.Id
join bc in DbContext.BrickColors on b.ColorId equals bc.Id
where ul.UserId == userId
group new { LocQty = ul.Quantity, LocBrickQty = lb.Quantity, Brick = b } by new { b.BrickId, b.ColorId }
into data
orderby data.Key
select new
{
Brick = data.FirstOrDefault().Brick,
Quantity = data.Sum(d => d.LocBrickQty * d.LocQty)
})
.AsNoTracking();
If I remove .AsNoTracking() the performance is quite good, because it keeps the BrickColors table in memory, but I want it to be included in the query from the start.
I have tried DbContext.Bricks.Include(b => b.BrickColorAccessor) in the query, but that doesn't work. I think my group new { } is messing something up since I don't include BrickColors there...

how to convert left join SQL script to Linq script?

How can I convert left join to linq script. I have a T-SQL like this:
SELECT
es.StandardID,
COUNT(DISTINCT esc.StandardCourseID) AS CourseIDCount,
COUNT(DISTINCT esp.StandardPostID) AS PostIDCount
FROM EduStandards AS es
LEFT JOIN EduStandardCourses AS esc
ON es.StandardID = esc.StandardID
LEFT JOIN EduStandardPosts AS esp
ON es.StandardID = esp.StandardID
GROUP BY es.StandardID
That I want to convert this to linq.
Following is the query with left join that is replica of your query in linq.
var query = (from es in dbContext.EduStandards
join esc in dbContext.EduStandardCourses on es.StandardID equals esc.StandardID into ssc
from esc in ssc.DefaultIfEmpty()
join esp in dbContext.EduStandardPosts on es.StandardID equals esp.StandardID into ssp
from esp in ssp.DefaultIfEmpty()
select new { StandardId = es.StandardID, CourseCount = ssc.Count(), PostCount = ssp.Count() }).Distinct().ToList();
But I think we need not to apply left join in linq to calculate count. Following optimized linq query will return same result.
var query2 = (from es in dbContext.EduStandards
join esc in dbContext.EduStandardCourses on es.StandardID equals esc.StandardID into ssc
join esp in dbContext.EduStandardPosts on es.StandardID equals esp.StandardID into ssp
select new { StandardId = es.StandardID, CourseCount = ssc.Count(), PostCount = ssp.Count() });
This is what I've come up with
var query = from es in db.EduStandards
join esc1 in db.EduStandardCourses
on es.StandardId equals esc1.StandardId into esc
from c in esc.DefaultIfEmpty()
join esp1 in db.EduStandardPosts
on es.StandardId equals esp1.StandardId into esp
from p in esp.DefaultIfEmpty()
group new { es.StandardId, Course = c, Post = p } by es.StandardId into g
select new
{
StandardId = g.Key,
CourseIdCount = g.Where(x => x.Course != null).Count(),
PostIdCount = g.Where(x => x.Post != null).Count(),
};
However, I'm not entirely sure if it'll work for EF.
You could always do something like this:
var query = from es in db.EduStandards
select new
{
es.StandardId,
CourseIdCount = db.EduStandardCourses.Where(esc => esc.StandardId == es.StandardId).Distinct().Count(),
PostIdCount = db.EduStandardPosts.Where(esp => esp.StandardId == es.StandardId).Distinct().Count()
};
Also, I can't attest to the performance of either one of these queries due to the lack of knowledge of your database.

SQL Query in LINQ to Entities

Can anyone tell me,how to write this query in LINQ?
select a.UTP_NAME, b.UPS_NAME, c.USS_NAME from
TB_UTILIDADE_PUBLIC_UTP a inner join
TB_UTILIDADE_PUBLIC_SECTOR_UPS b on
a.UPS_ID = b.UPS_ID
inner join TB_UTILIDADE_PUBLIC_SUBSECTOR_USS c
on a.USS_ID = c.USS_ID and a.UPS_ID = c.UPS_ID /* IMPORTANT LINE! */
Thanks.
Creating a new anonymous type allows you to join with multiple criteria
var query = from a in context.TB_UTILIDADE_PUBLIC_UTP
join b in context.TB_UTILIDADE_PUBLIC_SECTOR_UPS
on a.UPS_ID equals b.UPS_ID
join c in context.TB_UTILIDADE_PUBLIC_SUBSECTOR_USS
on new { a.USS_ID, a.UPS_ID } equals new { c.USS_ID, c.UPS_ID }
select new
{
a.UTP_NAME,
b.UPS_NAME,
c.USS_NAME
};

LINQ to SQL - How to add a where clause to a left join?

This LINQ query expression emits a left join and works:
from p in Prices
join ip in ItemPrices
on new { p.PriceId, ItemId = 7 } equals
new { ip.PriceId, ip.ItemId }
into priceItemPrice
from pip in priceItemPrice.DefaultIfEmpty()
select new
{
pricesPriceId = p.PriceId,
z = (int?)pip.PriceId,
p.Content,
p.PriceMinQ
}
SQL emitted:
-- Region Parameters
DECLARE #p0 Int = 7
-- EndRegion
SELECT [t0].[priceId] AS [pricesPriceId],
[t1].[priceId] AS [z],
[t0].[price] AS [Content],
[t0].[priceMinQ] AS [PriceMinQ]
FROM [price] AS [t0]
LEFT OUTER JOIN [itemPrice] AS [t1]
ON ([t0].[priceId] = [t1].[priceId])
AND (#p0 = [t1].[itemId])
How can I get it to emit the SQL below? It just has the where clause tacked on the end. A where clause is not accepted under the "from pip" and a where lambda expression before DefaultIfEmpty() doesn't work. I know I can filter it out in the select, but that's not what I need.
SELECT [t0].[priceId] AS [pricesPriceId],
[t1].[priceId] AS [z],
[t0].[price] AS [Content],
[t0].[priceMinQ] AS [PriceMinQ]
FROM [price] AS [t0]
LEFT OUTER JOIN [itemPrice] AS [t1]
ON ([t0].[priceId] = [t1].[priceId])
AND (#p0 = [t1].[itemId])
WHERE [t1].[priceId] is null
Update
Oy vey, my mistake, the where clause did work - for some reason VS2008 was not behaving and giving me grief and my stomach was growling. I tested back in LinqPad and the where clause was fine. So this little addition did work:
...
from pip in priceItemPrice.DefaultIfEmpty()
*** where pip.ItemId == null ***
select new
...
Here is a sample of how OneDotNetWay has done something similar. I've tried to take their example and match up your query.
var query = p in Prices
join ip in ItemPrices
on
new { p.PriceId, ItemId = 7 }
equals
new { ip.PriceId, ip.ItemId }
into priceItemPrice
from pip in priceItemPrice.DefaultIfEmpty()
select new
{
pricesPriceId = p.PriceId,
z = (int?)pip.PriceId,
p.Content,
p.PriceMinQ
}