Ho due tavoli in sql. Documento e utente Il documento ha una relazione con l'utente e voglio ottenere utenti che ho inviato documenti di recente.
Ho bisogno di ordinare per la data del documento è stato inviato e ottenere un utente unico (distinto) in relazione a questo documento
Questa è la mia query di linq
var recentClients = documentCaseRepository.Entities
.Where(docCase => docCase.AssignedByAgentId == WC.UserContext.UserId)
.OrderByDescending(userWithDate => userWithDate.LastUpdateDate)
.Take(1000) // I need this because if I comment this line then EF generate completely different sql query.
.Select(doc => new { doc.AssignedToClient.Id, doc.AssignedToClient.FirstName, doc.AssignedToClient.LastName })
.Distinct()
.Take(configuration.MaxRecentClientsResults)
.ToList();
e la query sql generata è:
SELECT DISTINCT TOP(5) [t].*
FROM (
SELECT TOP(1000) [docCase.AssignedToClient].[Id]
FROM [DocumentCase] AS [docCase]
INNER JOIN [User] AS [docCase.AssignedToClient]
ON ([docCase].[AssignedToClientId] = [docCase.AssignedToClient].[Id])
WHERE [docCase].[AssignedByAgentId] = 3
ORDER BY [docCase].[LastUpdateDate] DESC
)
AS [t]
Ogni cosa è corretta per ora. Ma se elimino questa linea
.Take(1000) // I need this because...
EF ha generato query completamente diverse come:
SELECT DISTINCT TOP(5)
[docCase.AssignedToClient].[Id]
FROM [DocumentCase] AS [docCase]
INNER JOIN [User] AS [docCase.AssignedToClient]
ON ([docCase].[AssignedToClientId] = [docCase.AssignedToClient].[Id])
WHERE [docCase].[AssignedByAgentId] = 3
La mia domanda è: perché EF non ha generato la clausola orderby e la sottoquery con distinti? Questo è un BUG EF o sto facendo qualcosa di sbagliato? E cosa devo fare per generare in linq questa query sql ()
SELECT DISTINCT TOP 5 [t].*
FROM ( SELECT [docCase.AssignedToClient].[Id]
FROM [DocumentCase] AS [docCase]
INNER JOIN [User] AS [docCase.AssignedToClient]
ON [docCase].[AssignedToClientId] = [docCase.AssignedToClient].[Id]
WHERE [docCase].[AssignedByAgentId] = 1
ORDER BY [docCase].[LastUpdateDate] DESC
) AS [t]
La ragione della differenza nelle query è che Distinct
rovina l'ordine dei risultati. Quindi, quando esegui OrderBy
prima volta e poi Distinct
, puoi semplicemente non eseguire OrderBy
, perché questo ordine viene comunque perso. Quindi EF può semplicemente ottimizzarlo.
Chiamare Take
in between fa sì che il risultato sia semanticamente diverso: per prima cosa ordini gli articoli, prendi i primi 1000 articoli di quell'ordine e poi chiama Distinct
su di essi.
Quello che puoi cambiare nella tua query dipende principalmente dal risultato che vuoi ottenere. Forse vuoi prima rendere il set di risultati distinto poi ordine per data e infine prendere la quantità di elementi. Altre opzioni sono pensabili in base alle tue esigenze.