Entity Framework 4 Single () vs First () vs FirstOrDefault ()

119

J'ai du mal à trouver une comparaison des différentes façons d'interroger un seul élément et quand les utiliser.

Quelqu'un a-t-il un lien qui compare tous ces éléments, ou une explication rapide de la raison pour laquelle vous utiliseriez l'un sur l'autre? Y a-t-il encore plus d'opérateurs que je ne connais pas?

Je vous remercie.

asfsadf
la source

Réponses:

205

Voici un aperçu des différentes méthodes:

  • Find () - lorsque vous souhaitez obtenir un élément par clé primaire. Cela renverra null s'il ne trouve pas d'élément. Il regardera dans le contexte avant d'aller dans la base de données (comme indiqué par Yaron dans les commentaires) qui peut être un facteur d'efficacité important si vous avez besoin d'obtenir la même entité plusieurs fois alors que le même contexte est vivant.

  • Single () - lorsque vous vous attendez à ce qu'un seul élément soit renvoyé par une requête. Cela lèvera une exception si la requête ne renvoie pas exactement un élément.

  • SingleOrDefault () - lorsque vous vous attendez à ce que zéro ou un élément soit renvoyé par une requête (c'est-à-dire que vous n'êtes pas sûr qu'un élément avec une clé donnée existe). Cela lèvera une exception si la requête ne renvoie aucun ou un élément.

  • First () - lorsque vous vous attendez à ce qu'un ou plusieurs éléments soient renvoyés par une requête mais que vous souhaitez uniquement accéder au premier élément de votre code (la commande peut être importante dans la requête ici). Cela lèvera une exception si la requête ne renvoie pas au moins un élément.

  • FirstOrDefault () - lorsque vous vous attendez à ce que zéro ou plusieurs éléments soient renvoyés par une requête mais que vous souhaitez uniquement accéder au premier élément de votre code (c'est-à-dire que vous n'êtes pas sûr qu'un élément avec une clé donnée existe)

Steve Willcock
la source
1
Cela dépend du scénario. Si vous savez que vous devriez toujours récupérer un seul enregistrement de la base de données, ni plus, ni moins, pour une requête donnée, alors Single () est le «bon» à utiliser. Dans d'autres situations, les autres peuvent être plus appropriés. Dans les versions précédentes d'EF, nous étions limités à First () et FirstOrDefault () qui fonctionnent pour les scénarios où vous attendez un seul enregistrement, mais ils ne vous avertiront pas si vous récupérez plus que cet enregistrement unique, ce qui pourrait être important en fonction de la situation.
Steve Willcock
1
Merci. Je ne me vois plus avoir besoin de First (), où Single () ne serait pas mieux. Si j'étais moins dense, je suis sûr que je pourrais apprécier / comprendre quand utiliser First () encore.
asfsadf
1
First () a plus de sens dans le cas où vous souhaitez récupérer uniquement l'objet avec le plus haut ou le plus bas de ce que vous commandez. Par exemple, trouvez-moi la vente avec la valeur totale la plus élevée. Sales.OrderByDescending(s => s.TotalValue).First();
Mike Chamberlain
5
Tous les commentaires semblent une différence importante. Find () est la seule méthode qui recherche le contexte avant d'atteindre la base de données.
Yaron Levi
5
Un autre point est lors de l'interrogation d'une base de données SQL, Singleou SingleOrDefaultinterrogera 2 enregistrements (limite 2) tandis que Firstou FirstOrDefaultinterrogera pour 1 (limite 1).
Bart Calixto
22

J'ai toujours tendance à utiliser FirstOrDefault. Si vous voulez vraiment être pointilleux avec les performances, vous devez utiliser FirstOrDefaultdans EF. Sous les couvertures SingleOrDefaultutilise top (2) dans la requête car, il doit vérifier s'il existe une deuxième ligne qui correspond aux critères et si c'est le cas, il lève une exception. Fondamentalement, SingleOrDefaultvous dites que vous souhaitez lever une exception si votre requête renvoie plus d'un enregistrement.

zeeshanhirani
la source
5
Avez-vous déjà mesuré la différence de performance entre FirstOrDefaultet SingleOrDefaultpour être significative? Je dirais que c'est une optimisation prématurée dans la plupart des cas.
Steven
J'ai tendance à utiliser Single()ou SingleOrDefault()quand je retourne quelque chose dont il devrait exister que l' un . La raison pour laquelle je le fais est de repérer les bogues en faisant des requêtes mal écrites, qui renvoient plus qu'elles ne le devraient, échouent. Au moins dans mon esprit, cela aidera à garder les données du système cohérentes. Bien sûr, c'est plus lent, mais je suppose que ce n'est pas beaucoup plus lent, et je suis prêt à payer ce prix.
mortb
15

C'est vraiment très simple: Singlerenvoie un seul élément et lance une exception s'il n'y a aucun ou plus d'un élément. Firstrenverra le premier article ou le lancera lorsqu'il n'y a pas d'article. FirstOrDefaultretournera le premier élément ou retournera la valeur par défaut (ce qui est nulldans le cas où le type donné est un type de référence) quand il n'y a pas d'élément.

C'est le comportement que l'API est censée avoir. Notez cependant que l'implémentation sous-jacente peut avoir un comportement différent. Alors qu'Entity Framework obéit à cela, un O / RM comme LLBLGen peut également revenir nulllors de l'appel, Firstce qui est une chose très étrange. C'était une décision très étrange (et têtue) de la part du designer IMO.

Steven
la source
Merci Steven. Je suppose que je me demande toujours pourquoi vous utiliseriez l'un sur l'autre? J'ai toujours utilisé FirstOrDefault (), et j'étais curieux de savoir pourquoi beaucoup de nouveaux exemples que j'ai vus sont passés à Single (). Y a-t-il une raison de passer à Single ()? Y en a-t-il d'autres qui accomplissent également la même chose, que je devrais plutôt envisager?
asfsadf
7
Si vous aimez que votre code "échoue rapidement", First () et Single () laissent votre code dire plus précisément ce qui est attendu (pour qu'il puisse échouer autrement)
Frank Schwieterman
3
Je suis totalement d'accord avec Frank. Il s'agit également de communiquer l'intention. Singleexprime clairement que vous vous attendez à ce que le résultat n'ait qu'un seul élément.
Steven
8

Les quatre méthodes ont chacune leur place; Bien que vous n'ayez vraiment que deux opérations différentes.

  • Premièrement - En attendant un jeu de résultats contenant plusieurs éléments, donnez-moi le premier élément de cet ensemble.
  • Simple - En attendant un seul résultat, donnez-moi cet élément.

La version xxxxOrDefault () ajoute simplement "Je ne veux pas considérer un jeu de résultats vide comme une circonstance exceptionnelle."

Chris Shaffer
la source
OK, il me semble donc que First () serait rarement utile. J'ai du mal à trouver un scénario où Single () ne serait pas la première option. Vous en avez un rapide, par hasard? Merci.
asfsadf
3
Malheureusement, beaucoup de développeurs utilisent First () ou FirstOrDefault () uniquement comme mesure défensive, pensant que cela évitera une exception alors qu'il a vraiment le potentiel de cacher de vrais problèmes.
Matt H
3

De l'autre côté, vous pouvez diviser ces méthodes par la logique de base, comme ceci:

  • La méthode interrogera directement la base de données : Single (), SingleOrDefault (), First (), FirstOrDefault ()
  • La méthode effectuera une recherche dans le cache avant même d'émettre la requête sur la base de données : Find ()

Pour quelques détails sur les performances, en particulier dans le second cas, vous pouvez regarder ici: https://msdn.microsoft.com/en-us/data/hh949853.aspx?f=255&MSPPError=-2147217396#3

De plus, dans le premier groupe, vous pouvez définir des requêtes complexes, mais avec la méthode Find () , vous ne pouvez fournir qu'une clé d'entité pour la recherche.

Kryszal
la source
0

Single () et SingleOrDefault () sont généralement utilisés sur des identificateurs uniques tels que les ID, tandis que First () ou FirstOrDefault () est généralement utilisé pour une requête qui pourrait avoir plusieurs résultats mais que vous ne voulez que "Top 1" .

Single () ou First () lèverait une exception si aucun résultat n'est renvoyé, SingleOrDefault () et FirstOrDefault () intercepte l'exception et renvoie null ou par défaut (ResultDataType).

MilkTea027
la source