web-dev-qa-db-fra.com

Avec Entity Framework, est-il préférable d'utiliser .First () ou .Take (1) pour "TOP 1"?

Nous implémentons certains référentiels de données EF et nous avons des requêtes qui incluraient TOP 1

J'ai lu de nombreux articles suggérant d'utiliser .Take(1)
Le code que j'examine utilise .First()

Je comprends que les deux produisent le même résultat pour l'affectation d'objet, mais résolvent-ils tous les deux à la même requête? Lorsque la base de données est interrogée, sera-t-elle réellement avec TOP 1 Pour les deux demandes? Ou exécuteront-ils la requête dans son intégralité dans l'énumérable, puis prendront-ils simplement la première entrée de la collection?

De plus, si nous avons utilisé .FirstOrDefault() alors pourquoi devrions-nous nous attendre à un comportement différent? Je sais que lorsque vous utilisez un IEnumerable, appeler .First() sur une collection vide lancera, mais si cela is ne fait que changer la requête pour inclure TOP 1 Alors je devrais ne vous attendez à aucune différence fonctionnelle entre .First() et .FirstOrDefault().... non?

Sinon, existe-t-il une meilleure méthode que ces extensions énumérables pour faire exécuter la requête TOP 1?

39
Matthew

De LINQPad :

C # :

age_Centers.Select(c => c.Id).First();
age_Centers.Select(c => c.Id).FirstOrDefault();
age_Centers.Select(c => c.Id).Take(1).Dump();

[~ # ~] sql [~ # ~] :

SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]
GO

SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]
GO

SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]

* Notez que Take(1) énumère et retourne un IQueryable.

74
ken

Redirigez la propriété DataContext Log vers Console.Out d'un fichier texte et voyez quelle requête chaque option produit.

5
Icarus
**First()** operates on a collection of any number of objects and returns the first object.        **Take(1)** operates on a collection of any number of objects and returns a collection containing the first object.

Vous pouvez également utiliser Single Single () fonctionne sur une collection d'exactement un objet et renvoie simplement l'objet.

2
Vishal Pandey

Fonctionnement de .First():

Si la collection est de type IList, le premier élément est accessible par la position d'index qui est différente selon l'implémentation de la collection. Sinon, un itérateur renvoie le premier élément.

Et .Take(int count) itère toujours.

S'il y a un gain, cela se produit si la collection implémente IList et que la vitesse d'accès au premier élément par index est supérieure à celle de retour d'un itérateur. Je ne pense pas que ce sera important. ;)

Sources:

http://www.hookedonlinq.com/FirstOperator.ashx

http://www.hookedonlinq.com/TakeOperator.ashx

1
Lucas Reis

Le premier interrogera Take 1, il n'y a donc aucune différence dans la requête. L'appel à FirstOrDefault sera une instruction en une étape, car Take renvoie IEnumerable, vous devrez quand même appeler First.

First lèvera une exception donc FirstOrDefault est toujours préféré.

Et bien sûr, les personnes qui ont écrit le convertisseur de requête EF sont assez intelligentes pour appeler Take 1 au lieu d'exécuter l'ensemble de résultats et de renvoyer le premier élément.

Vous pouvez le vérifier à l'aide du profileur SQL.

1
Akash Kava