Entity Framework Core : query improvement - c#
I'm new to EF, I have a database in which a certain table contains keys of a number of other tables, it is the central table from which I go to the other tables (ProductIdentifiers).
The input to the query is not id, but the Name which is not defined as any key.
Here's my Entity Framework query :
public ProductIdentifier? GetFullCedMed(string v)
=> db.ProductIdentifiers.Where(a => a.Name == v)
.Include(ced => ced.Project)
.Include(ced => ced.LimitValues).ThenInclude(l => l.Parameter)
.Include(ced => ced.LimitValues).ThenInclude(l => l.Bin)
.Include(ced => ced.LimitValues).ThenInclude(l => l.Stage)
.Include(ced => ced.LimitValues).ThenInclude(l => l.TestTypeNavigation)
.Include(ced => ced.ConfigValues).ThenInclude(c => c.Parameter)
.Include(ced => ced.ConfigValues).ThenInclude(c => c.Bin)
.Include(ced => ced.ConfigValues).ThenInclude(c => c.Stage)
.Include(ced => ced.ConfigValues).ThenInclude(c => c.TestTypeNavigation)
.Include(ced => ced.FatherCedmed)
.ToList().FirstOrDefault();
The code is converted to a SQL query that looks like this:
exec sp_executesql N'SELECT [p].[id], [p].[FatherCedmedId], [p].[Name], [p].[ProjectId], [m].[id], [m].[IsActive], [m].[Name], [m].[ProductLineName], [p0].[id], [t].[id], [t].[BinId], [t].[CED_MED], [t].[LSL], [t].[ParameterID], [t].[StageID], [t].[TestType], [t].[USL], [t].[id0], [t].[Enabled], [t].[FORMAT], [t].[IsLimit], [t].[ParamID], [t].[Parameter_Name], [t].[Print], [t].[Unit], [t].[id1], [t].[BinDescription], [t].[BinDescriptionOverride], [t].[BinNumber], [t].[BinNumberOverride], [t].[GroupID], [t].[ParamID0], [t].[StageID0], [t].[id2], [t].[Name], [t].[StageNumber], [t].[id3], [t].[LevelId], [t].[Name0], [t].[OrderingId], [t0].[id], [t0].[BinId], [t0].[CED_MED], [t0].[ParameterID], [t0].[StageID], [t0].[TestType], [t0].[Value], [t0].[id0], [t0].[Enabled], [t0].[FORMAT], [t0].[IsLimit], [t0].[ParamID], [t0].[Parameter_Name], [t0].[Print], [t0].[Unit], [t0].[id1], [t0].[BinDescription], [t0].[BinDescriptionOverride], [t0].[BinNumber], [t0].[BinNumberOverride], [t0].[GroupID], [t0].[ParamID0], [t0].[StageID0], [t0].[id2], [t0].[Name], [t0].[StageNumber], [t0].[id3], [t0].[LevelId], [t0].[Name0], [t0].[OrderingId], [p0].[FatherCedmedId], [p0].[Name], [p0].[ProjectId]
FROM [ProductIdentifiers] AS [p]
LEFT JOIN [main_Projects] AS [m] ON [p].[ProjectId] = [m].[id]
LEFT JOIN [ProductIdentifiers] AS [p0] ON [p].[FatherCedmedId] = [p0].[id]
LEFT JOIN (
SELECT [l].[id], [l].[BinId], [l].[CED_MED], [l].[LSL], [l].[ParameterID], [l].[StageID], [l].[TestType], [l].[USL], [p1].[id] AS [id0], [p1].[Enabled], [p1].[FORMAT], [p1].[IsLimit], [p1].[ParamID], [p1].[Parameter_Name], [p1].[Print], [p1].[Unit], [b].[id] AS [id1], [b].[BinDescription], [b].[BinDescriptionOverride], [b].[BinNumber], [b].[BinNumberOverride], [b].[GroupID], [b].[ParamID] AS [ParamID0], [b].[StageID] AS [StageID0], [s].[id] AS [id2], [s].[Name], [s].[StageNumber], [m0].[id] AS [id3], [m0].[LevelId], [m0].[Name] AS [Name0], [m0].[OrderingId]
FROM [LimitValues] AS [l]
INNER JOIN [Parameters] AS [p1] ON [l].[ParameterID] = [p1].[id]
INNER JOIN [Bins] AS [b] ON [l].[BinId] = [b].[id]
LEFT JOIN [Stages] AS [s] ON [l].[StageID] = [s].[id]
LEFT JOIN [main_TestTypes] AS [m0] ON [l].[TestType] = [m0].[id]
) AS [t] ON [p].[id] = [t].[CED_MED]
LEFT JOIN (
SELECT [c].[id], [c].[BinId], [c].[CED_MED], [c].[ParameterID], [c].[StageID], [c].[TestType], [c].[Value], [p2].[id] AS [id0], [p2].[Enabled], [p2].[FORMAT], [p2].[IsLimit], [p2].[ParamID], [p2].[Parameter_Name], [p2].[Print], [p2].[Unit], [b0].[id] AS [id1], [b0].[BinDescription], [b0].[BinDescriptionOverride], [b0].[BinNumber], [b0].[BinNumberOverride], [b0].[GroupID], [b0].[ParamID] AS [ParamID0], [b0].[StageID] AS [StageID0], [s0].[id] AS [id2], [s0].[Name], [s0].[StageNumber], [m1].[id] AS [id3], [m1].[LevelId], [m1].[Name] AS [Name0], [m1].[OrderingId]
FROM [ConfigValues] AS [c]
INNER JOIN [Parameters] AS [p2] ON [c].[ParameterID] = [p2].[id]
INNER JOIN [Bins] AS [b0] ON [c].[BinId] = [b0].[id]
LEFT JOIN [Stages] AS [s0] ON [c].[StageID] = [s0].[id]
LEFT JOIN [main_TestTypes] AS [m1] ON [c].[TestType] = [m1].[id]
) AS [t0] ON [p].[id] = [t0].[CED_MED]
WHERE [p].[Name] = #__v_0
ORDER BY [p].[id], [m].[id], [p0].[id], [t].[id], [t].[id0], [t].[id1], [t].[id2], [t].[id3], [t0].[id], [t0].[id0], [t0].[id1], [t0].[id2]',N'#__v_0 varchar(255)',#__v_0='NAME_OF_RECORD_FROM_ProductIdentifier_TABLE'
Pay attention to the input in the ORDER BY line.
My question is: how can the query be improved?
The tables contain a lot of data and the query takes a lot of time.
Will retrieval by ID make it faster? Indicates that all the data is relevant for me, which means that it is necessary to join all the tables.
Thanks for any other advice.
for creating separated query and getting better performance use .AsSplitQuery()
Related
EF Core Include translates to SQL with sub queries that have no filters
Meetings .Include(a => a.Document) .Include(a => a.Plan) .Include(a => a.User) .Include(a => a.Topics).ThenInclude(e => e.Extra) .Include(a => a.Components).ThenInclude(g => g.Extra) .Include(a => a.Recipients).ThenInclude(i => i.Info) .Single(a => a.MeetingId == 1) The above LINQ will translate to SQLs with sub queries that have no filters: SELECT [blah] FROM ( SELECT TOP(2) [blah] FROM [Meeting] AS [m] LEFT JOIN [Plan] AS [s] ON [m].[PlanId] = [s].[PlanId] LEFT JOIN [User] AS [u] ON [m].[UserId] = [u].[Id] WHERE [m].[MeetingId] = 1 ) AS [t] LEFT JOIN [Document] AS [m0] ON [t].[MeetingId] = [m0].[MeetingId] LEFT JOIN ( SELECT [blah] FROM [Topic] AS [m1] LEFT JOIN [Extra] AS [a] ON [m1].[ExtraId] = [a].[ExtraId] ) AS [t0] ON [t].[MeetingId] = [t0].[MeetingId] LEFT JOIN ( SELECT [blah] FROM [Component] AS [m2] LEFT JOIN [Extra] AS [a0] ON [m2].[ExtraId] = [a0].[ExtraId] ) AS [t1] ON [t].[MeetingId] = [t1].[MeetingId] LEFT JOIN ( SELECT [blah] FROM [Recipient] AS [m3] INNER JOIN [Info] AS [l] ON [m3].[InfoId] = [l].[InfoId] ) AS [t2] ON [t].[MeetingId] = [t2].[MeetingId] If you look at the last 3 joins, there are no filters so they will scan the whole table. Is there a way to fix this? This is EF Core 3.1 btw.
EF Core difficulty with INNER JOINS and LEFT JOINS
I am trying to retrieve some data from a very big database. In order to retrieve it I need to get some data from within 6 inner joins. The following options is what I tried already: Option 1 Using EF Core en ThenInclude var enquiry = await _context.Enquiries .Where(e => e.Id == id) .Include(e => e.EnqPartJobs.Where(ej => ej.RecordStateId == 0)) .ThenInclude(ej => ej.AnswerGrpBatch) .ThenInclude(agb => agb.AnswerGrps) .ThenInclude(ag => ag.EnqPropResults) .ThenInclude(epr => epr.EnqPropResultDevs) .ThenInclude(epr => epr.Deviation) .ToListAsync(); The advantage of this method is that it will map nicely in a Enquiry class with a list of AnswerGrpBatches. Btw I did not name these classes this is just how the database looks. When looking at the query it is the following: SELECT [e].[SID], [e].[FK_CRMPartner_SID], [e].[FK_Certificate_SID], [e].[createDate], [e].[displayDate], [e].[extID], [e].[finishDate], [e].[fixedGenId], [e].[aName], [t2].[SID], [t2].[FK_Enquiry_SID], [t2].[aName], [t2].[FK_RecordState_SID], [t2].[remark], [t2].[validFrom], [t2].[validTo], [t2].[SID0], [t2].[FK_EnqPartJob_SID], [t2].[FK_RecordState_SID0], [t2].[SID1], [t2].[FK_AnswerGrpBatch_SID], [t2].[FK_RecordState_SID1], [t2].[SID00], [t2].[FK_AnswerGrp_SID], [t2].[FK_EnqPropertyForm_SID], [t2].[FK_PossResult_SID], [t2].[FK_RecordState_SID00], [t2].[value], [t2].[SID000], [t2].[FK_Deviation_SID], [t2].[FK_EnqPropResult_SID], [t2].[SID0000], [t2].[aDescription], [t2].[aName0] FROM [Enquiry] AS [e] LEFT JOIN ( SELECT [e0].[SID], [e0].[FK_Enquiry_SID], [e0].[aName], [e0].[FK_RecordState_SID], [e0].[remark], [e0].[validFrom], [e0].[validTo], [a].[SID] AS [SID0], [a].[FK_EnqPartJob_SID], [a].[FK_RecordState_SID] AS [FK_RecordState_SID0], [t1].[SID] AS [SID1], [t1].[FK_AnswerGrpBatch_SID], [t1].[FK_RecordState_SID] AS [FK_RecordState_SID1], [t1].[SID0] AS [SID00], [t1].[FK_AnswerGrp_SID], [t1].[FK_EnqPropertyForm_SID], [t1].[FK_PossResult_SID], [t1].[FK_RecordState_SID0] AS [FK_RecordState_SID00], [t1].[value], [t1].[SID00] AS [SID000], [t1].[FK_Deviation_SID], [t1].[FK_EnqPropResult_SID], [t1].[SID000] AS [SID0000], [t1].[aDescription], [t1].[aName] AS [aName0] FROM [EnqPartJob] AS [e0] LEFT JOIN [AnswerGrpBatch] AS [a] ON [e0].[SID] = [a].[FK_EnqPartJob_SID] LEFT JOIN ( SELECT [a0].[SID], [a0].[FK_AnswerGrpBatch_SID], [a0].[FK_RecordState_SID], [t0].[SID] AS [SID0], [t0].[FK_AnswerGrp_SID], [t0].[FK_EnqPropertyForm_SID], [t0].[FK_PossResult_SID], [t0].[FK_RecordState_SID] AS [FK_RecordState_SID0], [t0].[value], [t0].[SID0] AS [SID00], [t0].[FK_Deviation_SID], [t0].[FK_EnqPropResult_SID], [t0].[SID00] AS [SID000], [t0].[aDescription], [t0].[aName] FROM [AnswerGrp] AS [a0] LEFT JOIN ( SELECT [e1].[SID], [e1].[FK_AnswerGrp_SID], [e1].[FK_EnqPropertyForm_SID], [e1].[FK_PossResult_SID], [e1].[FK_RecordState_SID], [e1].[value], [t].[SID] AS [SID0], [t].[FK_Deviation_SID], [t].[FK_EnqPropResult_SID], [t].[SID0] AS [SID00], [t].[aDescription], [t].[aName] FROM [EnqPropResult] AS [e1] LEFT JOIN ( SELECT [e2].[SID], [e2].[FK_Deviation_SID], [e2].[FK_EnqPropResult_SID], [d].[SID] AS [SID0], [d].[aDescription], [d].[aName] FROM [EnqPropResultDev] AS [e2] INNER JOIN [Deviation] AS [d] ON [e2].[FK_Deviation_SID] = [d].[SID] ) AS [t] ON [e1].[SID] = [t].[FK_EnqPropResult_SID] ) AS [t0] ON [a0].[SID] = [t0].[FK_AnswerGrp_SID] ) AS [t1] ON [a].[SID] = [t1].[FK_AnswerGrpBatch_SID] WHERE [e0].[FK_RecordState_SID] = 0 ) AS [t2] ON [e].[SID] = [t2].[FK_Enquiry_SID] WHERE [e].[SID] = 1790797 But it needs to be one of these 2 options: using a IS NOT NULL statement but I cannot figure out how to make this one beceause it is deep inside different classes. SELECT [e].[SID], [e].[FK_CRMPartner_SID], [e].[FK_Certificate_SID], [e].[createDate], [e].[displayDate], [e].[extID], [e].[finishDate], [e].[fixedGenId], [e].[aName], [t2].[SID], [t2].[FK_Enquiry_SID], [t2].[aName], [t2].[FK_RecordState_SID], [t2].[remark], [t2].[validFrom], [t2].[validTo], [t2].[SID0], [t2].[FK_EnqPartJob_SID], [t2].[FK_RecordState_SID0], [t2].[SID1], [t2].[FK_AnswerGrpBatch_SID], [t2].[FK_RecordState_SID1], [t2].[SID00], [t2].[FK_AnswerGrp_SID], [t2].[FK_EnqPropertyForm_SID], [t2].[FK_PossResult_SID], [t2].[FK_RecordState_SID00], [t2].[value], [t2].[SID000], [t2].[FK_Deviation_SID], [t2].[FK_EnqPropResult_SID], [t2].[SID0000], [t2].[aDescription], [t2].[aName0] FROM [Enquiry] AS [e] LEFT JOIN ( SELECT [e0].[SID], [e0].[FK_Enquiry_SID], [e0].[aName], [e0].[FK_RecordState_SID], [e0].[remark], [e0].[validFrom], [e0].[validTo], [a].[SID] AS [SID0], [a].[FK_EnqPartJob_SID], [a].[FK_RecordState_SID] AS [FK_RecordState_SID0], [t1].[SID] AS [SID1], [t1].[FK_AnswerGrpBatch_SID], [t1].[FK_RecordState_SID] AS [FK_RecordState_SID1], [t1].[SID0] AS [SID00], [t1].[FK_AnswerGrp_SID], [t1].[FK_EnqPropertyForm_SID], [t1].[FK_PossResult_SID], [t1].[FK_RecordState_SID0] AS [FK_RecordState_SID00], [t1].[value], [t1].[SID00] AS [SID000], [t1].[FK_Deviation_SID], [t1].[FK_EnqPropResult_SID], [t1].[SID000] AS [SID0000], [t1].[aDescription], [t1].[aName] AS [aName0] FROM [EnqPartJob] AS [e0] LEFT JOIN [AnswerGrpBatch] AS [a] ON [e0].[SID] = [a].[FK_EnqPartJob_SID] LEFT JOIN ( SELECT [a0].[SID], [a0].[FK_AnswerGrpBatch_SID], [a0].[FK_RecordState_SID], [t0].[SID] AS [SID0], [t0].[FK_AnswerGrp_SID], [t0].[FK_EnqPropertyForm_SID], [t0].[FK_PossResult_SID], [t0].[FK_RecordState_SID] AS [FK_RecordState_SID0], [t0].[value], [t0].[SID0] AS [SID00], [t0].[FK_Deviation_SID], [t0].[FK_EnqPropResult_SID], [t0].[SID00] AS [SID000], [t0].[aDescription], [t0].[aName] FROM [AnswerGrp] AS [a0] LEFT JOIN ( SELECT [e1].[SID], [e1].[FK_AnswerGrp_SID], [e1].[FK_EnqPropertyForm_SID], [e1].[FK_PossResult_SID], [e1].[FK_RecordState_SID], [e1].[value], [t].[SID] AS [SID0], [t].[FK_Deviation_SID], [t].[FK_EnqPropResult_SID], [t].[SID0] AS [SID00], [t].[aDescription], [t].[aName] FROM [EnqPropResult] AS [e1] LEFT JOIN ( SELECT [e2].[SID], [e2].[FK_Deviation_SID], [e2].[FK_EnqPropResult_SID], [d].[SID] AS [SID0], [d].[aDescription], [d].[aName] FROM [EnqPropResultDev] AS [e2] INNER JOIN [Deviation] AS [d] ON [e2].[FK_Deviation_SID] = [d].[SID] ) AS [t] ON [e1].[SID] = [t].[FK_EnqPropResult_SID] ) AS [t0] ON [a0].[SID] = [t0].[FK_AnswerGrp_SID] ) AS [t1] ON [a].[SID] = [t1].[FK_AnswerGrpBatch_SID] WHERE [e0].[FK_RecordState_SID] = 0 ) AS [t2] ON [e].[SID] = [t2].[FK_Enquiry_SID] WHERE [e].[SID] = 1790797 AND [t2].[SID000] IS NOT NULL Forcing INNER JOINS: SELECT [e].[SID], [e].[FK_CRMPartner_SID], [e].[FK_Certificate_SID], [e].[createDate], [e].[displayDate], [e].[extID], [e].[finishDate], [e].[fixedGenId], [e].[aName], [t2].[SID], [t2].[FK_Enquiry_SID], [t2].[aName], [t2].[FK_RecordState_SID], [t2].[remark], [t2].[validFrom], [t2].[validTo], [t2].[SID0], [t2].[FK_EnqPartJob_SID], [t2].[FK_RecordState_SID0], [t2].[SID1], [t2].[FK_AnswerGrpBatch_SID], [t2].[FK_RecordState_SID1], [t2].[SID00], [t2].[FK_AnswerGrp_SID], [t2].[FK_EnqPropertyForm_SID], [t2].[FK_PossResult_SID], [t2].[FK_RecordState_SID00], [t2].[value], [t2].[SID000], [t2].[FK_Deviation_SID], [t2].[FK_EnqPropResult_SID], [t2].[SID0000], [t2].[aDescription], [t2].[aName0] FROM [Enquiry] AS [e] LEFT JOIN ( SELECT [e0].[SID], [e0].[FK_Enquiry_SID], [e0].[aName], [e0].[FK_RecordState_SID], [e0].[remark], [e0].[validFrom], [e0].[validTo], [a].[SID] AS [SID0], [a].[FK_EnqPartJob_SID], [a].[FK_RecordState_SID] AS [FK_RecordState_SID0], [t1].[SID] AS [SID1], [t1].[FK_AnswerGrpBatch_SID], [t1].[FK_RecordState_SID] AS [FK_RecordState_SID1], [t1].[SID0] AS [SID00], [t1].[FK_AnswerGrp_SID], [t1].[FK_EnqPropertyForm_SID], [t1].[FK_PossResult_SID], [t1].[FK_RecordState_SID0] AS [FK_RecordState_SID00], [t1].[value], [t1].[SID00] AS [SID000], [t1].[FK_Deviation_SID], [t1].[FK_EnqPropResult_SID], [t1].[SID000] AS [SID0000], [t1].[aDescription], [t1].[aName] AS [aName0] FROM [EnqPartJob] AS [e0] LEFT JOIN [AnswerGrpBatch] AS [a] ON [e0].[SID] = [a].[FK_EnqPartJob_SID] LEFT JOIN ( SELECT [a0].[SID], [a0].[FK_AnswerGrpBatch_SID], [a0].[FK_RecordState_SID], [t0].[SID] AS [SID0], [t0].[FK_AnswerGrp_SID], [t0].[FK_EnqPropertyForm_SID], [t0].[FK_PossResult_SID], [t0].[FK_RecordState_SID] AS [FK_RecordState_SID0], [t0].[value], [t0].[SID0] AS [SID00], [t0].[FK_Deviation_SID], [t0].[FK_EnqPropResult_SID], [t0].[SID00] AS [SID000], [t0].[aDescription], [t0].[aName] FROM [AnswerGrp] AS [a0] INNER JOIN ( SELECT [e1].[SID], [e1].[FK_AnswerGrp_SID], [e1].[FK_EnqPropertyForm_SID], [e1].[FK_PossResult_SID], [e1].[FK_RecordState_SID], [e1].[value], [t].[SID] AS [SID0], [t].[FK_Deviation_SID], [t].[FK_EnqPropResult_SID], [t].[SID0] AS [SID00], [t].[aDescription], [t].[aName] FROM [EnqPropResult] AS [e1] INNER JOIN ( SELECT [e2].[SID], [e2].[FK_Deviation_SID], [e2].[FK_EnqPropResult_SID], [d].[SID] AS [SID0], [d].[aDescription], [d].[aName] FROM [EnqPropResultDev] AS [e2] INNER JOIN [Deviation] AS [d] ON [e2].[FK_Deviation_SID] = [d].[SID] ) AS [t] ON [e1].[SID] = [t].[FK_EnqPropResult_SID] ) AS [t0] ON [a0].[SID] = [t0].[FK_AnswerGrp_SID] ) AS [t1] ON [a].[SID] = [t1].[FK_AnswerGrpBatch_SID] WHERE [e0].[FK_RecordState_SID] = 0 ) AS [t2] ON [e].[SID] = [t2].[FK_Enquiry_SID] WHERE [e].[SID] = 1790797 The problem is that it will use Left Joins for every Include and ThenInclude except the last one. But this will also retrieve information that I do not need. So I tried to make a LINQ query. Option 2 LINQ The LINQ query always uses INNER JOINS, so I exactly get what I want from the database. The only problem is that I have no clue how to map this to an Enquiry class where the INNER JOINS are a list within the Enquiry class. Just like with option 1. var query = from enquiry in _context.Set<Enquiry>() join enqPartJob in _context.Set<EnqPartJob>() on enquiry.Id equals enqPartJob.EnquiryId join answerGrpBatch in _context.Set<AnswerGrpBatch>() on enqPartJob.Id equals answerGrpBatch.EnqPartJobId join answerGrp in _context.Set<AnswerGrp>() on answerGrpBatch.Id equals answerGrp.AnswerGrpBatchId join enqPropResult in _context.Set<EnqPropResult>() on answerGrp.Id equals enqPropResult.AnswerGrpId join enqPropResultDev in _context.Set<EnqPropResultDev>() on enqPropResult.Id equals enqPropResultDev.EnqPropResultId join deviation in _context.Set<Deviation>() on enqPropResultDev.DeviationId equals deviation.Id where enquiry.Id == id select new { enquiry, enqPropResultDev }; And yis I get that there is a reason EFCore uses LEFT JOINS but this is not my datbase so I have to adapt to it.
Thx to Ivan Stoev who commented this suggestion. Starting with Deviation and working my way up to Enquiry did the trick for me. The query now looks like this (as you can see it contains INNER JOINS). SELECT [t].[SID], [t].[aDescription], [t].[aName], [t0].[SID], [t0].[FK_Deviation_SID], [t0].[FK_EnqPropResult_SID], [t0].[SID0], [t0].[FK_AnswerGrp_SID], [t0].[FK_EnqPropertyForm_SID], [t0].[FK_PossResult_SID], [t0].[FK_RecordState_SID], [t0].[value], [t0].[SID1], [t0].[FK_AnswerGrpBatch_SID], [t0].[FK_RecordState_SID0], [t0].[SID2], [t0].[FK_EnqPartJob_SID], [t0].[FK_RecordState_SID1], [t0].[SID3], [t0].[FK_Enquiry_SID], [t0].[aName], [t0].[FK_RecordState_SID2], [t0].[remark], [t0].[validFrom], [t0].[validTo], [t0].[SID4], [t0].[FK_CRMPartner_SID], [t0].[FK_Certificate_SID], [t0].[createDate], [t0].[displayDate], [t0].[extID], [t0].[finishDate], [t0].[fixedGenId], [t0].[aName0] FROM ( SELECT TOP(1) [d].[SID], [d].[aDescription], [d].[aName] FROM [Deviation] AS [d] WHERE [d].[SID] = 5038 ) AS [t] LEFT JOIN ( SELECT [e].[SID], [e].[FK_Deviation_SID], [e].[FK_EnqPropResult_SID], [e0].[SID] AS [SID0], [e0].[FK_AnswerGrp_SID], [e0].[FK_EnqPropertyForm_SID], [e0].[FK_PossResult_SID], [e0].[FK_RecordState_SID], [e0].[value], [a].[SID] AS [SID1], [a].[FK_AnswerGrpBatch_SID], [a].[FK_RecordState_SID] AS [FK_RecordState_SID0], [a0].[SID] AS [SID2], [a0].[FK_EnqPartJob_SID], [a0].[FK_RecordState_SID] AS [FK_RecordState_SID1], [e1].[SID] AS [SID3], [e1].[FK_Enquiry_SID], [e1].[aName], [e1].[FK_RecordState_SID] AS [FK_RecordState_SID2], [e1].[remark], [e1].[validFrom], [e1].[validTo], [e2].[SID] AS [SID4], [e2].[FK_CRMPartner_SID], [e2].[FK_Certificate_SID], [e2].[createDate], [e2].[displayDate], [e2].[extID], [e2].[finishDate], [e2].[fixedGenId], [e2].[aName] AS [aName0] FROM [EnqPropResultDev] AS [e] INNER JOIN [EnqPropResult] AS [e0] ON [e].[FK_EnqPropResult_SID] = [e0].[SID] INNER JOIN [AnswerGrp] AS [a] ON [e0].[FK_AnswerGrp_SID] = [a].[SID] INNER JOIN [AnswerGrpBatch] AS [a0] ON [a].[FK_AnswerGrpBatch_SID] = [a0].[SID] INNER JOIN [EnqPartJob] AS [e1] ON [a0].[FK_EnqPartJob_SID] = [e1].[SID] INNER JOIN [Enquiry] AS [e2] ON [e1].[FK_Enquiry_SID] = [e2].[SID] WHERE [e0].[FK_RecordState_SID] = 0 ) AS [t0] ON [t].[SID] = [t0].[FK_Deviation_SID] ORDER BY [t].[SID], [t0].[SID], [t0].[SID0], [t0].[SID1], [t0].[SID2], [t0].[SID3], [t0].[SID4]
How to improve LINQ statement to use INNER JOIN in resulting SQL statement?
Assuming the following code that applies filtering logic to a passed on collection. private IQueryable<Customer> ApplyCustomerFilter(CustomerFilter filter, IQueryable<Customer> customers) { ... if (filter.HasProductInBackOrder == true) { customers = customers.Where(c => c.Orders.Any(o => o.Products.Any(p => p.Status == ProductStatus.BackOrder))) } .... return customers; } Results in this SQL statement: SELECT [Extent1].[CustomerId] AS [CustomerId], [Extent1].[Status] AS [Status] FROM [Customers] AS [Extent1] WHERE ( EXISTS ( SELECT 1 AS [C1] FROM ( SELECT [Extent3].[OrderId] AS [OrderId] FROM [Orders] AS [Extent3] WHERE [Extent1].[CustomerId] = [Extent3].[CustomerId] ) AS [Project1] WHERE EXISTS ( SELECT 1 AS [C1] FROM [Products] AS [Extent4] WHERE ([Project1].[OrderId] = [Extent4].[OrderId]) AND ([Extent4].[Status] = #p__linq__6) ) ) ) However, I would like to optimize this by forcing to use INNER JOINS so that the result will be similar to this: SELECT [Extent1].[CustomerId] AS [CustomerId], [Extent1].[Status] AS [Status] FROM [Customers] AS [Extent1] INNER JOIN [Orders] AS [Extent2] ON [Extent1].[CustomerId] = [Extent2].[CustomerId] INNER JOIN [Products] AS [Extent3] ON [Extent2].[OrderId] = [Extent3].[OrderId] WHERE [Extent3].[Status] = #p__linq__6 I've tried multiple approaches, but I was unable to accomplish the desired result. Any suggestions on how to force the correct joins and avoiding subselects?
How to do a where in subquery using Entity Framework?
I have a query like: var result = from u in this.DataContext.Users join l in DataContext.Locations on u.Id equals l.userId where u.active == 1 select u; return result ; I want to add a subquery WHERE IN clause like: WHERE u.Id IN (SELECT userId FROM approved_users) Is this possible?
I am not sure why you want it in a sub query, it seems simpler to just join the Approved Users table, but I do not know the requirement so I have presented two options. One option that has a sub query and one option with the additional join. I am also making an assumption that you don't have any navigation properties. Option 1 - Subquery: var subQuery = from u in context.Users.Where(x => context.ApprovedUsers.Select(y => y.ApprovedUserId).Contains(x.UserId)) join l in context.Locations on u.UserId equals l.UserId where u.IsActive == true select u; which generates something like this SELECT [Extent1].[UserId] AS [UserId], [Extent1].[Name] AS [Name], [Extent1].[IsActive] AS [IsActive] FROM [dbo].[User] AS [Extent1] INNER JOIN [dbo].[Location] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[UserId] WHERE ( EXISTS (SELECT 1 AS [C1] FROM [dbo].[ApprovedUser] AS [Extent3] WHERE [Extent3].[ApprovedUserId] = [Extent1].[UserId] )) AND (1 = [Extent1].[IsActive]) Option 2 - Additional Join: var query = from u in context.Users join l in context.Locations on u.UserId equals l.UserId join au in context.ApprovedUsers on u.UserId equals au.ApprovedUserId where u.IsActive == true select u; which generates: SELECT [Extent1].[UserId] AS [UserId], [Extent1].[Name] AS [Name], [Extent1].[IsActive] AS [IsActive] FROM [dbo].[User] AS [Extent1] INNER JOIN [dbo].[Location] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[UserId] INNER JOIN [dbo].[ApprovedUser] AS [Extent3] ON [Extent1].[UserId] = [Extent3].[ApprovedUserId] WHERE 1 = [Extent1].[IsActive]
How to write linq query to prevent duplicates joins?
I have a query that search for all accommodations in an order, sorted by day. When I check on the sever what query is executed, I see multiple join toward the same table on the same keys var parcourt = this.DataService.From<OrderItem>() .Where(i => i.OrderId == orderId && i.Product.ProductTypeId == (int)ProductTypes.Accommodation) .OrderBy(i => i.DayNumber) .ThenBy(i => i.OrderItemId) .Select(i => new { i.OrderItemId, i.DayNumber, i.Product.Establishment.Address, i.Product.Establishment.Coordinates }); If you check the resulting SQL (as show by ToTraceString), you can see two join on the Products and Establishments table. SELECT [Project1].[OrderItemId] AS [OrderItemId], [Project1].[DayNumber] AS [DayNumber], [Project1].[Address] AS [Address], [Project1].[EstablishmentId] AS [EstablishmentId], [Project1].[Latitude] AS [Latitude], [Project1].[Longitude] AS [Longitude] FROM ( SELECT [Extent1].[OrderItemId] AS [OrderItemId], [Extent1].[DayNumber] AS [DayNumber], [Extent4].[Address] AS [Address], [Extent5].[EstablishmentId] AS [EstablishmentId], [Extent5].[Latitude] AS [Latitude], [Extent5].[Longitude] AS [Longitude] FROM [dbo].[OrderItems] AS [Extent1] INNER JOIN [dbo].[Products] AS [Extent2] ON [Extent1].[ProductId] = [Extent2].[ProductId] LEFT OUTER JOIN [dbo].[Products] AS [Extent3] ON [Extent1].[ProductId] = [Extent3].[ProductId] LEFT OUTER JOIN [dbo].[Establishments] AS [Extent4] ON [Extent3].[EstablishmentId] = [Extent4].[EstablishmentId] LEFT OUTER JOIN [dbo].[Establishments] AS [Extent5] ON [Extent3].[EstablishmentId] = [Extent5].[EstablishmentId] WHERE (1 = [Extent2].[ProductTypeId]) AND ([Extent1].[OrderId] = #p__linq__0) ) AS [Project1] ORDER BY [Project1].[DayNumber] ASC, [Project1].[OrderItemId] ASC How can I prevent this linq-to-entities from joining twice on a table? How can I rewrite the query to avoid this situation? The table structure goes as follow (simplified): This is the query
Could you try this query? I think if you call all your joins explicitly, it'll not create joins automatically. var parcourt = (from i in this.DataService.OrderItem join p in this.DataService.Product on p.ProductId equals i.ProductId join e in this.DataService.Establishments on e.EstablishmentId equals p.EstablishmentId where i.OrderId == orderId && p.ProductTypeId == (int)ProductTypes.Accomodation orderby i.DayNumber, i.OrderItemId select new { i.OrderItemId, i.DayNumber, e.Address, e.Coordinates });