linq to entities Not in statement - linq

I am new to linq to entities. I am trying to do a not in statement and when i run it i am getting noting back. But if i run the SQL equivalent i get data back.
The SQL statement that i am trying to replicate is
SELECT * FROM [SCRAPREASON] WHERE [CODE] NOT IN (SELECT [CODE] FROM [QUALITYALERTRULE]) ORDER BY [CODE]
The Linq i have at the moment is
var DefectCode = PumaOEEEntities.ScrapReasons
.Where(x => !PumaOEEEntities.QualityAlertRules.Any(y => y.Code != x.Code))
.Select(x => new { GroupID = x.Code}).ToList();
Can anyone see what i am doing wrong?

You should compare codes for equality (== instead of !=):
var reasons = PumaOEEEntities.ScrapReasons
.Where(x => !PumaOEEEntities.QualityAlertRules.Any(y => y.Code == x.Code))
.OrderBy(x => x.Code)
.ToList();
Generated SQL will look like:
SELECT
[Extent1].[Code] AS [Code],
// Other columns
FROM [dbo].[ScrapReasons] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[QualityAlertRules] AS [Extent2]
WHERE [Extent2].[Code] = [Extent1].[Code]
)
ORDER BY [Extent1].[Code] ASC

You can try Except like this
var DefectCode = PumaOEEEntities.ScrapReasons.Select(x=>x.Code)
.Except(PumaOEEEntities.QualityAlertRules.Select(y=>y.Code)).ToList();

Related

Transform Sql to EF Core Linq query

I am trying to translate the following query from SQL to EF Core. I can easily just use a stored procedure (I already have the SQL), but am trying to learn how some of the linq queries work. Unfortunately this is not by any means an ideal database schema that I inherited and I don't have the time to convert it to something better.
DECLARE #userId INT = 3
SELECT *
FROM dbo.CardGamePairs
WHERE EXISTS (SELECT 1
FROM dbo.Users
WHERE Users.Id = CardGamePairs.player1Id
AND Users.userId = #userId)
UNION
SELECT *
FROM dbo.CardGamePairs
WHERE EXISTS (SELECT 1
FROM dbo.Users
WHERE Users.Id = TableB.player2Id
AND Users.userId = #userId)
So basically I have an id that can exist in one of two separate columns in table b and I don't know in which column it may be in, but I need all rows that have that ID in either column. The following is what I tried to make this work:
//Find data from table A where id matches (part of the subquery from above)
var userResults = _userRepository.GetAllAsQueryable(x => x.userId == userId).ToList();
//Get data from table b
var cardGamePairsResults = _cardGamePairsRepository.GetAllAsQueryable(x => userResults .Any(y => y.userId == x.player1Id || y.userId == x.player2Id));
When I run the code above I get this error message:
predicate: (y) => y.userId == x.player1Id || y.userId == x.player2Id))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
Any ideas on how I can make this work? (I tried changing the column and table names to something that would actually make sense, hopefully I didn't miss any spots and make it more confusing.)
Because you are already have user id use it to query both columns.
var userResults = _userRepository
.GetAllAsQueryable(x => x.userId == userId)
.ToList();
var cardGamePairsResults = _cardGamePairsRepository
.GetAllAsQueryable(x => x.player1Id == userId || x.player2Id == userId));

Inner Join with two equalities inside on clause in LINQ Lambda

I'm trying to convert a Sql query to a Linq Lambda style query. Thought this would be something easy but it turned out not.
SQL Query is as follows;
select distinct t1.ID from table1 t1
inner Join table2 t2on (t2.FromId= t1.Id or t2.ToId= t1.Id)
where t1.TenantId = 12
and t2.wId= 51
All examples I came across are for one clause joins so far. I wrote something like this
actStaList = _db.t1
.Join(_db.t2,
s => s.ID,
wf => wf.ToId,
(s, wf) => new { t1= s, t2= wf }
)
.Where(a => a.t1.Tenant.Guid == _tenantGuid)
.Select (m=>m.t1.ID)
.ToList();
It is obvious this won't work as the sql query above but still it's a start.
Still I can't figure where should I add the second part inside INNER JOIN and Distinct keyword.
One option you have is to use two separate Linq Queries and concat the result(and eliminating duplicates).
var left = t1.Join(t2,
s => s.ID,
wf => wf.ToId,
(s, wf) => new { t1= s, t2= wf }
).Select(x=>x);
var right = t1.Join(t2,
s => s.ID,
wf => wf.FromId,
(s, wf) => new { t1= s, t2= wf }
).Select(x=>x);
var actStaList = left.Concat(right).Select(m=>m.t1.ID)
.Distinct();
Please note I have omitted the Where Clause in the example as in the OP, both Sql version and your attempted Linq version seem to have different conditions. You can add them yourself.
The LINQ Join statement only supports equi-joins. For other types of equality you can't use the Join statement and have to code the equality manually. This is much easier in query syntax:
actStaList = (
from t1 in _db.table1
from t2 in _db.table2
where t2.FromId == t1.Id || t2.ToId == t1.Id
where t1.TenantId == 12 && t2.wId == 51
select t1.ID
).Distinct();
For the record, you can avoid the Distinct statement by executing this as a SQL EXISTS statement:
actStaList =
from t1 in _db.table1
where t1.TenantId == 12
where (from t2 in _db.table2
where t2.wId == 51 && (t2.FromId == t1.Id || t2.ToId == t1.Id)
select t2).Any()
select t1.ID;

How to convert SQL inner join to lambda linq query

I am new in LINQ queries
and I need help to convert my sample SQL query to LINQ lambda query
select * from GRecommendations
inner join GSections
on GRecommendations.GSectionId = GSections.Id
where GSections.GaId = 646
There are two different methods you can use when GRecommendations is a collection.
var arrResult = //UNTESTED
GRecommendations
.Join(GSections.Where(sec => sec.GaId.Equals(646)),
rec => rec.GeSectionId,
sec => sec.Id,
(REC, SEC) => new { /*put here what you want selected*/ }
); //
or
var arrResult =
(
from rec in GRecommendations
join rec in GSections.Where(s => s.GaId.Equals(646)) on rec.GSectionId equals sec.GaId
select new {/*rec.something*/, /*sec.something*/}
);

linq 'not in' query not resolving to what I expect

I've written the following query in Linq:
var res = dc.TransactionLoggings
.Where(
x => !dc.TrsMessages(y => y.DocId != x.DocId)
).Select(x => x.CCHMessage).ToList();
This resolves to the following:
SELECT [t0].[CCHMessage]
FROM [dbo].[TransactionLogging] AS [t0]
WHERE NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[TrsMessages] AS [t1]
WHERE [t1].[DocId] <> [t0].[DocId]
))
Which always returns null
Basiaclly what I'm trying to write is the following :
Select cchmessage
from transactionlogging
where docid not in (select docid from trsmessages)
Any suggestions on what's wrong with my LINQ statment?
var res = dc.TransactionLoggings
.Where(tl => !dc.TrsMessages.Any(trsm=> trsm.DocId == tl.DocId))
.Select(x => x.CCHMessage).ToList();
or
var trsMessagesDocId = dc.TrsMessages.Select(trsm => trsm.DocId).ToList();
var res = dc.TransactionLoggins
.Where(tl => !trsMessagesDocId.Contains(tl.DocId))
.Select(tl => tl.CCHMEssage)
.ToList();

How do I use subquery, groupby, max, and top in single linqToSql statement?

Using LinqToSql, I need to return a single (L) for the most recent modDate in a join table (CL).
Tables:
L (Lid, meta1, meta2, ...)
CL (Cid, Lid, ModDate)
Here is sql that produces the expected result
SELECT l.*
FROM L l
INNER JOIN (
SELECT TOP 1 cl.Lid, MAX(cl.ModDate) as ModDate
FROM CL cl
INNER JOIN L l ON cl.Lid = l.Lid AND l.meta1 = 5
GROUP BY cl.Lid
ORDER BY MAX(cl.ModDate) DESC
) As m ON l.Lid = m.Lid
Simple enough. The subquery projects us to the ids. The query fetches those records with matching ids.
var subquery = db.L
.Where(L => L.meta1 = 5)
.SelectMany(L => L.CLs)
.GroupBy(CL => CL.Lid)
.OrderByDescending(g => g.Max(CL => CL.ModDate))
.Select(g => g.Key)
.Take(1)
var query = db.L
.Where(L => subquery.Any(id => L.Lid == id))
Reflecting on this further, you can get away from the subquery:
var query = db.L
.Where(L => L.meta1 = 5)
.SelectMany(L => L.CLs)
.GroupBy(CL => CL.Lid)
.OrderByDescending(g => g.Max(CL => CL.ModDate))
.Select(g => g.First().L);
As your provided query, I can interpret into this Linq.
var query = from l in Context.L
join m in (from cl in Context.CL
join l in Context.L on cl.Lid equals l.Lid
where l.meta1 == 5
group new { l.Lid, cl.ModDate } by cl.Lid into grp
select new { Lid = grp.Key, ModDate = grp.Max(g => g.ModDate) } into grp
order by grp.ModDate descending
select grp).Take(1) on l.Lid equals m.Lid
select l;
My SQL-fu isn't fabulous and it's before my first coffee, so I assume "l" in the outer query ends up being a completely different "l" to the one in the subquery?
I think this will do it, but you'll have to try to be sure :) It'll be well worth checking what the generated SQL looks like. If you didn't mind it executing as two queries, of course, it would be somewhat simpler.
// Can't do the "Take(1)" here or it will be executed separately
var subquery = from cl in context.CL
join l in context.L on cl.Lid = l.Lid
where l.meta1 = 5 // could put this in join clause
group cl.ModDate by cl.lid into grouped
order by grouped.Max() descending
select grouped.Key;
// But can take the first result of the join
// This may be simpler using dot notation instead of a query expression
var query = (from l in context.L
join lid in subquery
select l).Take(1);
(EDIT: I wasn't taking the max ModDate before. Doh. Also simplified grouping by using the ID as the key (which it was already) so we only need the ModDate as the group values.)

Resources