La sequencia no contiene elementos coincidentes


112

Tengo una aplicación asp.net en la que estoy usando linq para la manipulación de datos. Mientras se ejecuta, obtengo la excepción "La secuencia no contiene ningún elemento coincidente".

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;
        }
    }
}

Respuestas:


220

Bueno, esperaría que sea esta línea la que arroje la excepción:

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

First()lanzará una excepción si no puede encontrar ningún elemento coincidente. Dado que está probando nulo inmediatamente después, parece que lo desea FirstOrDefault(), lo que devuelve el valor predeterminado para el tipo de elemento (que es nulo para los tipos de referencia) si no se encuentran elementos coincidentes:

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

Otras opciones a considerar en algunas situaciones son Single()(cuando cree que hay exactamente un elemento coincidente) y SingleOrDefault()(cuando cree que hay exactamente uno o cero elementos coincidentes). Sospecho que FirstOrDefaultes la mejor opción en este caso particular, pero vale la pena conocer las demás de todos modos.

Por otro lado, parece que, en primer lugar, podría estar mejor con una combinación aquí. Si no le importaba que hiciera todas las coincidencias (en lugar de solo la primera), puede usar:

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
}

Eso es IMO más simple y más eficiente.

Incluso si usted no decide mantener el bucle, tengo un par de sugerencias:

  • Deshazte del exterior if. No lo necesita, como si Count fuera cero, el cuerpo del bucle for nunca se ejecutará
  • Use límites superiores exclusivos en bucles for; son más idiomáticos en C #:

    for (i = 0; i < _lstAcl.Documents.Count; i++)
  • Eliminar subexpresiones comunes:

    var target = _lstAcl.Documents[i];
    // Now use target for the rest of the loop body
  • Cuando sea posible, utilice en foreachlugar de forcomenzar con:

    foreach (var target in _lstAcl.Documents)

39

Utilice FirstOrDefault . Primero nunca devolverá un valor nulo; si no puede encontrar un elemento coincidente, arroja la excepción que está viendo.

_dsACL.Documents.FirstOrDefault(o => o.ID == id);

19
Solo para aclarar un poco: primero podría devolver un valor nulo en general, si su predicado coincide con valores nulos. Simplemente no puede devolver un valor nulo aquí, ya o.IDque arrojaría una excepción NullReferenceException en un valor nulo.
Jon Skeet

11

Desde la biblioteca de MSDN:

El First<TSource>(IEnumerable<TSource>)método lanza una excepción si la fuente no contiene elementos. En su lugar, para devolver un valor predeterminado cuando la secuencia de origen está vacía, use el FirstOrDefaultmétodo.


0

Para aquellos de ustedes que enfrentaron este problema al crear un controlador a través del menú contextual, reabrir Visual Studio como administrador lo solucionó.


-4

Tal vez usar Where () antes de First () pueda ayudarlo, ya que mi problema se ha resuelto en este caso.

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

3
Lo que realmente te ha ayudado aquí es usar .FirstOrDefault () en lugar de .First () - usando .Where (o => o.ID == id) .FirstOrDefault () y .FirstOrDefault (o => o.ID == id ) será idéntico.
pwdst

@pwdst usando la condición en la cláusula Where y luego FirstOrDefault sin ninguna expresión lambda.
Elnaz
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.