La séquence ne contient aucun élément correspondant

112

J'ai une application asp.net dans laquelle j'utilise linq pour la manipulation de données. En cours d'exécution, j'obtiens l'exception "La séquence ne contient aucun élément correspondant".

if (_lstAcl.Documents.Count > 0)
{
    for (i = 0; i <= _lstAcl.Documents.Count - 1; i++)
    {
        string id = _lstAcl.Documents[i].ID.ToString();                           
        var documentRow = _dsACL.Documents.First(o => o.ID == id);
        if (documentRow !=null)
        {

            _lstAcl.Documents[i].Read = documentRow.Read;
            _lstAcl.Documents[i].ReadRule = documentRow.ReadRule;

            _lstAcl.Documents[i].Create= documentRow.Create;
            _lstAcl.Documents[i].CreateRule = documentRow.CreateRule;

            _lstAcl.Documents[i].Update = documentRow.Update;
            _lstAcl.Documents[i].UpdateRule = documentRow.UpdateRule;

            _lstAcl.Documents[i].Delete = documentRow.Delete;
            _lstAcl.Documents[i].DeleteRule = documentRow.DeleteRule;
        }
    }
}
MAC
la source

Réponses:

220

Eh bien, je m'attendrais à ce que ce soit cette ligne qui jette l'exception:

var documentRow = _dsACL.Documents.First(o => o.ID == id)

First()lèvera une exception s'il ne trouve aucun élément correspondant. Étant donné que vous testez la valeur null immédiatement après, cela ressemble à ce que vous voulez FirstOrDefault(), ce qui renvoie la valeur par défaut du type d'élément (qui est null pour les types de référence) si aucun élément correspondant n'est trouvé:

var documentRow = _dsACL.Documents.FirstOrDefault(o => o.ID == id)

D'autres options à considérer dans certaines situations sont Single()(lorsque vous pensez qu'il y a exactement un élément correspondant) et SingleOrDefault()(lorsque vous pensez qu'il y a exactement un ou zéro élément correspondant). Je soupçonne que FirstOrDefaultc'est la meilleure option dans ce cas particulier, mais cela vaut quand même la peine de connaître les autres.

D'un autre côté, il semble que vous seriez peut-être mieux avec une jointure ici en premier lieu. Si vous ne vous souciez pas qu'il fasse toutes les correspondances (plutôt que la première), vous pouvez utiliser:

var query = from target in _lstAcl.Documents
            join source in _dsAcl.Document
            where source.ID.ToString() equals target.ID
            select new { source, target };
foreach (var pair in query)
{
    target.Read = source.Read;
    target.ReadRule = source.ReadRule;
    // etc
}

C'est l' OMI plus simple et plus efficace.

Même si vous ne décidez de garder la boucle, j'ai quelques suggestions:

  • Débarrassez-vous de l'extérieur if. Vous n'en avez pas besoin, comme si Count était égal à zéro, le corps de la boucle for ne s'exécutera jamais
  • Utilisez des limites supérieures exclusives dans les boucles for - elles sont plus idiomatiques en C #:

    for (i = 0; i < _lstAcl.Documents.Count; i++)
  • Éliminez les sous-expressions courantes:

    var target = _lstAcl.Documents[i];
    // Now use target for the rest of the loop body
  • Si possible, utilisez foreachau lieu de forpour commencer:

    foreach (var target in _lstAcl.Documents)
Jon Skeet
la source
39

Utilisez FirstOrDefault . First ne retournera jamais null - s'il ne trouve pas d'élément correspondant, il lève l'exception que vous voyez.

_dsACL.Documents.FirstOrDefault(o => o.ID == id);
Jakub Konecki
la source
19
Juste pour clarifier légèrement - First pourrait renvoyer null en général, si votre prédicat correspondait à des valeurs nulles. Il ne peut tout simplement pas retourner null ici, comme le o.IDferait une NullReferenceException sur une valeur null.
Jon Skeet
11

À partir de la bibliothèque MSDN:

La First<TSource>(IEnumerable<TSource>)méthode lève une exception si la source ne contient aucun élément. Pour renvoyer à la place une valeur par défaut lorsque la séquence source est vide, utilisez la FirstOrDefaultméthode.

KBoek
la source
0

Pour ceux d'entre vous qui ont rencontré ce problème lors de la création d'un contrôleur via le menu contextuel, la réouverture de Visual Studio en tant qu'administrateur l'a résolu.

Cendre
la source
-4

Peut-être que l'utilisation de Where () avant First () peut vous aider, car mon problème a été résolu dans ce cas.

var documentRow = _dsACL.Documents.Where(o => o.ID == id).FirstOrDefault();
Elnaz
la source
3
Ce qui vous a réellement aidé ici, c'est d'utiliser .FirstOrDefault () au lieu de .First () - en utilisant .Where (o => o.ID == id) .FirstOrDefault () et .FirstOrDefault (o => o.ID == id ) sera identique.
pwdst
@pwdst en utilisant la condition de la clause Where, puis FirstOrDefault sans aucune expression lambda.
Elnaz