web-dev-qa-db-fra.com

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

J'ai une application asp.net dans laquelle j'utilise linq pour la manipulation de données. Pendant l'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;
        }
    }
}
100
MAC

Eh bien, je suppose que c'est 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, il semble que vous souhaitiez FirstOrDefault() , qui renvoie la valeur par défaut du type d'élément (qui est null pour les types de référence) si no les articles correspondants sont trouvés:

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

Les autres options à considérer dans certaines situations sont Single() (lorsque vous croyez qu'il existe exactement un élément correspondant) et SingleOrDefault() (lorsque vous crois qu'il y a exactement un ou zéro éléments correspondants). Je soupçonne que FirstOrDefault est la meilleure option dans ce cas particulier, mais il est intéressant de connaître les autres.

D'un autre côté, il semblerait que vous pourriez en fait être mieux avec une jointure ici en premier lieu. Si vous ne vous souciez pas que cela ferait tout correspond (plutôt que le premier), vous pourriez 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 plus simple et plus efficace à l’OMI.

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

  • Débarrassez-vous du if extérieur. Vous n'en avez pas besoin, car si Count vaut 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++)
    
  • Éliminer les sous-expressions courantes:

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

    foreach (var target in _lstAcl.Documents)
    
197
Jon Skeet

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);
31
Jakub Konecki

à partir de la bibliothèque MSDN: La méthode First (IEnumerable) lève une exception si la source ne contient aucun élément. Pour renvoyer une valeur par défaut lorsque la séquence source est vide, utilisez la méthode FirstOrDefault

10
KBoek

Pour ceux d'entre vous qui ont fait face à 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 a résolu le problème.

0
Ash