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

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();

Related

Linq Query with Max Effective Date

Having trouble understanding how i can convert the following SQL Query into LINQ. Specifically the MAX effective date parts.
SELECT A.NAME, X.XLATLONGNAME AS ACTION, C.DESCR, B.EFFDT
FROM ACTN_REASON_TBL C, XLATTABLE X, PERSONAL_DATA A, JOB B
WHERE A.EMPLID = B.EMPLID
AND B.ACTION = C.ACTION(+)
AND B.ACTION_REASON = C.ACTION_REASON(+)
AND (C.EFFDT = (SELECT MAX(C_ED.EFFDT) FROM ACTN_REASON_TBL C_ED
WHERE C.ACTION = C_ED.ACTION
AND C.ACTION_REASON = C_ED.ACTION_REASON
AND C_ED.EFFDT <= B.EFFDT)
OR C.EFFDT IS NULL)
AND X.FIELDNAME = 'ACTION'
AND B.ACTION = X.FIELDVALUE
AND X.EFFDT = (SELECT MAX(X_ED.EFFDT) FROM XLATTABLE X_ED
WHERE X.FIELDNAME = X_ED.FIELDNAME
AND X.LANGUAGE_CD = X_ED.LANGUAGE_CD
AND X.FIELDVALUE = X_ED.FIELDVALUE
AND X_ED.EFFDT <= SYSDATE)
AND B.ACTION_DT BETWEEN sysdate - 30 AND sysdate
AND B.ACTION NOT IN ('EOI','NBY','LIF','FSC','LOA','LTD','PLA','RFL','PAY')
ORDER BY A.NAME, B.EFFDT DESC
This is what i have so far for my LINQ query...
public ActionResult RecentTransaction()
{
RecentTransViewModel recTransModel = new RecentTransViewModel();
var minusThirty = DateTime.Today.AddDays(-90);
var today = DateTime.Now;
var exceptionList = new List<string> { "EOI", "NBY", "LIF", "FSC", "LOA", "LTD", "PLA", "RFL", "PAY" };
var transaction = (from p in recentTrans.PERSONAL_DATA
join j in recentTrans.JOB on p.EMPLID equals j.EMPLID
join a in recentTrans.ACTN_REASON_TBL on j.ACTION_REASON equals a.ACTION_REASON
join x in recentTrans.XLATTABLE_VW on j.ACTION equals x.FIELDVALUE
where x.FIELDNAME == "ACTION"
where j.ACTION_DT >= minusThirty
where j.ACTION_DT <= today
where !exceptionList.Contains(j.ACTION)
select new RecentTransViewModel
{
Name = p.NAME,
Action = x.XLATLONGNAME,
Descr = a.DESCR,
EffectiveDate = j.EFFDT
}).OrderBy(d => d.Name)
.ToList();
return View(transaction);
Any help is greatly appriciated!
LINQ allows you to add nested Queries within the same contex so that you can:
select new RecentTransViewModel
{
Name = p.NAME,
Action = x.XLATLONGNAME,
Descr = a.DESCR,
EffectiveDate = EffectiveDate = (from eft in recentTrans.XLATTABLE_VW
where eft.FIELDNAME == x.FIELDNAME AND eft.LANGUAGE_CD = X.LANGUAGE_CD AND
eft.FIELDVALUE = x.FIELDVALUE AND eft.EFFDT <= SYSDATE
select eft).Max(c=> c.EFFDT)
}).OrderBy(d => d.Name)
.ToList();

linq to entities Not in statement

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();

Using subquery in entity framework

I am trying to write the entity framework linq query to generate the following SQL. But I am not sure how to use subqueries with entity framework.
The Sql I want to generate is:
Declare #StartDate Datetime2; Set #Startdate = '2014-Feb-16 09:52'
Declare #EndDate Datetime2; Set #Enddate = '2014-Feb-18 09:52'
SELECT
[D].[RefId]
,[D].[StatusId]
,[D].[StatusDate]
,[D].[Reference]
,[RSC].[Event]
,[RSC].[Information]
,[RSC].[CreatedDate]
FROM (
SELECT
[R].[RefId]
,[R].[StatusId]
,[R].[StatusDate]
,[I].[Reference]
,(SELECT TOP 1
[RSC].[ChangeId]
FROM
[dbo].[StateChangeTable] AS [RSC] (nolock)
WHERE
[RSC].[RefId] = [R].[RefId]
ORDER BY
[RSC].[ChangeId] DESC) AS [LastChangeId]
FROM
[dbo].[Table1] AS [R] (nolock)
INNER JOIN
[dbo].[Table2] AS [I] (nolock)
ON
[R].[RefId] = [I].[RefId]
WHERE
[R].[StatusId] IN (4, 6)
AND [R].[StatusDate] between #StartDate and #EndDate
) AS [D]
INNER JOIN
[dbo].[StateChangeTable] AS [RSC] (nolock)
ON
[D].[LastChangeId] = [RSC].[ChangeId
]
And the code I wrote till now is:
return this.DbContext.Table1
.Join(this.DbContext.Table2, rc => rc.RefId, ri => ri.RefId, (rc, ri) => new { rc, ri })
.Join(this.DbContext.StateChangeTable, request => request.ri.RefId, rsc => rsc.RefId, (request, rsc) => new {request, rsc})
.Where(r => (r.rsc.ChangeId == ((from rsc in this.DbContext.StateChangeTable
orderby rsc.ChangeId descending
select rsc.ChangeId).FirstOrDefault())) &&
(r.request.rc.StatusId == 4 || r.request.rc.StatusId == 6) &&
(r.request.rc.StatusDate >= startDateTime && r.request.rc.StatusDate <= endDateTime))
.Select(requestDetails => new StatusDetail
{
RefId = requestDetails.request.rc.RefId,
StatusDate = requestDetails.request.rc.StatusDate,
StatusId = requestDetails.request.rc.StatusId,
Reference = requestDetails.request.ri.DistributionReference.Value,
Event = requestDetails.rsc.Event,
CreatedDate = requestDetails.rsc.CreatedDate,
Information = requestDetails.rsc.Information
}).ToList();
Can some please let me know what I am doing wrong?
Many Thanks
Here is the Full query
var query = (from D in
((from tab1 in DbContext.Table1
join tab2 in DbContext.Table2 on tab1.RefId equals tab2.RefId
where (tab1.StatusId == 4 || tab1.StatusId == 6)
&& (tab1.StatusDate >= startDate && tab1.StatusDate <= endDate)
select new
{
RefId = tab1.RefId,
StatusId = tab1.StatusId,
StatusDate = tab1.StatusDate,
Reference = tab2.Reference,
LastChangeId = (from RSC in DbContext.StateChangeTable
where RSC.RefId == tab1.RefId
orderby RSC.ChangeId descending
select RSC.ChangeId).FirstOrDefault()
}))
join RSC in DbContext.StateChangeTable on D.LastChangeId equals RSC.ChangeId
select new StatusDetail
{
RefId = D.RefId,
StatusId = D.StatusId,
StatusDate = D.StatusDate,
Reference = D.Reference,
Event = RSC.Event,
Information = RSC.Information,
CreatedDate = RSC.CreatedDate
}).ToList();
Don't use .Join() you have to use the navigation properties on your entities.

How to write this LINQ Query in a better way

I have one Linq Query. When I run the query, Only for 10 records its taking 13 seconds to extract the data to the model. I need to know the query which I wrote is good for performance or not. Please guide me what i am doing wrong.
Code
var stocktakelist = (from a in Db.Stocktakes
select new ExportStock
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = (from admin in Db.AdminAccounts where admin.Id == a.Id select admin.Name).FirstOrDefault(),
CreatedOn = a.CreatedOn,
Status = (from items in Db.Items where items.ItemNo == a.ItemNo select items.ItemStatu.Description).FirstOrDefault(),
Title = (from tit in Db.BibContents where tit.BibId == (from bibs in Db.Items where bibs.ItemNo == a.ItemNo select bibs.BibId).FirstOrDefault() && tit.TagNo == "245" && tit.Sfld == "a" select tit.Value).FirstOrDefault() // This line of Query only makes the performance Issue
}
).ToList();
Thanks
The reason this is so slow is because it is running the 3 inner LINQ statements for every item in the outer LINQ statement.
Using LINQ joins will run only 4 queries and then link them together, which is faster.
To find out how to join, there are plenty of resources on the Internet depending on the type of LINQ you are using.
If you're retrieving this data from a SQL server, perhaps consider doing this intensive work in SQL - this is what SQL was designed for and it's much quicker than .NET. EDIT: As highlighted below, the work is done in SQL if using LINQ to SQL/Entities and using the correct join syntax.
I was trying to create the corresponding query with some joins for practice.
I cannot test it and i'm not 100% sure that this query will you get the result
you are hoping for but maybe at least it will give you a hint on how to write
joins with linq.
from a in Db.Stocktakes
join admin in Db.AdminAccounts
on a.Id equals admin.Id
into adminJoinData
from adminJoinRecord in adminJoinData.DefaultIfEmpty( )
join items in Db.Items
on a.ItemNo equals items.ItemNo
into itemsJoinData
from itemsJoinRecord in itemsJoinData.DefaultIfEmpty( )
join title in Db.BibContents
(
from subQuery in Db.BibContents
where subQuery.TagNo == "245"
where subQuery.Sfld == "a"
select subquery
)
on title.BibId equals itemsJoinRecord.BidId
into titleJoinData
from titleJoinRecord in titleJoinData.DefaultIfEmpty( )
select new ExportStock( )
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = adminJoinRecord.Name,
CreatedOn = a.CreatedOn,
Status = itemsJoinRecord.ImemStatu.Description,
Title = titleJoinRecord.Value
}
As others have said, you should use Left Outer Joins in your LINQ just as you would if writing it in SQL.
Your query above will end up looking roughly like this once converted (this is untested, but gives the basic idea):
var a = from a in Db.Stocktakes
join admin in Db.AdminAccounts on admin.Id equals a.Id into tmpAdmin
from ad in tmpAdmin.DefaultIfEmpty()
join item in Db.Items on item.ItemNo equals a.ItemNo into tmpItem
from it in tmpItem.DefaultIfEmpty()
join title in Db.BibContents on bib.BibId equals items.BibId into tmpTitle
from ti in tmpTitle.DefaultIfEmpty()
where ti.TagNo == "245"
&& ti.Sfld == "a"
select new ExportStock
{
Id = a.Id,
ItemNo = a.ItemNo,
AdminId = ad == null ? default(int?) : ad.Id,
CreatedOn = a.CreatedOn,
Status = it == null ? default(string) : it.ItemStatus.Description,
Title = ti == null ? default(string) : ti.Value
};
Using lambda expressions your query will look like this:
Db.Stocktakes
.Join(Db.AdminAccounts, a => a.Id, b => b.Id, (a,b) => new { a, AdminId = b.Name })
.Join(Db.Items, a => a.ItemNo, b => b.ItemNo, (a,b) => new { a, Status = b.ItemStatus.Description, BidId = b.BibId })
.Join(Db.BibContents, a => a.BibId, b => b.BibId, (a,b) => new { a, Value = b.Value, TagNo = b.TagNo, Sfld = b.Sfld })
.Where(a => a.TagNo == "245" && a.Sfld == "a")
.Select(a =>
new ExportStock { Id = a.Id,
ItemNo = a.ItemNo,
AdminId = a.AdminId,
CreatedOn = a.CreatedOn,
Status = a.Status,
Title = a.Value
}
).ToList();

linq query, convert sql query to linq for VB.net

I am trying to get fields from one table and max(expirationDate) from another table. This is my original linq query:
tanks = (From t In db.Table1 _
Where t.CompanyID = txtCompanyID.Text.Trim() _
Join d In db.Table2 On t.TankID Equals d.TankID
Order By d.ExpireDate Descending
Select t).ToList
that brings back multiple expireDates, I only want the max(expireDate) for each record
The following sql query works, I just need to put it into a linq query
select t1.*,
(Select MAX(Table2.ExpireDate)
from Table2 as t2
where t2.TankID = t1.TankID)
as max_expire_date
from Table1 as t1
where t1.CompanyID = '5467'
order by t1.CargoTankID
Does anybody know how to get this into linq? Thanks
tanks = db.Table1.Where( t => t.CompanyId == txtCompanyID.Text.Trim() )
.Join( db.Table2, t1 => t1.TankID, t2 => t2.TankID, (t1,t2) => new { Company = t1, t2.ExpireDate } )
.GroupBy( t => t.Company, (c,e) => new { Company = c Expiration = e.Max( x => x.ExpireDate ) } )
.ToList();
Best guess at VB
Dim tanks = db.Table1.Where( Function(t) t.CompanyId == txtCompanyID.Text.Trim() ) _
.Join( db.Table2, Function(t1) t1.TankID, Function(t2) t2.TankID, Function(t1,t2) New Thing With { .Company = t1, .ExpireDate = t2.ExpireDate } ) _
.GroupBy( Function(t) t.Company, Function(c,e) New Thing With { .Company = c, .Expiration = e.Max( Function(x) x.ExpireDate ) } ) _
.ToList()

Resources