2010-10-22 27 views
82

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

Respuesta

163

Bueno, yo esperaría que es esta línea que está lanzando la excepción:

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

First() lanzará una excepción si no puede encontrar todos los elementos coincidentes. Teniendo en cuenta que se está probando para nula inmediatamente después, parece que usted quiere FirstOrDefault(), que devuelve el valor predeterminado para el tipo de elemento (que es nula para los tipos de referencia) si no hay elementos coincidentes se encuentran:

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

Otros Las opciones a tener en cuenta en algunas situaciones son Single() (cuando crees que hay exactamente un elemento coincidente) y SingleOrDefault() (cuando crees que hay exactamente uno o cero elementos coincidentes). Sospecho que FirstOrDefault es la mejor opción en este caso particular, pero vale la pena saber de los demás de todos modos.

Por otro lado, parece que en realidad estarás mejor con una unión aquí en primer lugar. Si no le importa que lo haría todos los partidos (en lugar de sólo la primera) se puede utilizar:

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 más simple y más eficiente de la OMI.

Incluso si haces deciden mantener el lazo, que tienen un par de sugerencias:

  • Deshacerse de la if exterior. Usted no lo necesita, como si Contador es cero para el cuerpo del bucle sin ejecutará
  • Use límites superiores exclusivos en los bucles - son más idiomática 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 
    
  • Siempre que sea posible el uso foreach en lugar de comenzar con for:

    foreach (var target in _lstAcl.Documents) 
    
26

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

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

Solo para aclarar un poco - Primero * podría * devolver nulo en general, si su predicado coincidía con valores nulos. Simplemente no puede devolver nulo aquí, ya que 'o.ID' arrojaría una NullReferenceException en un valor nulo. –

+2

@Jon Skeet: +1 - tienes razón. –

9

de la biblioteca de MSDN: El primer método (IEnumerable) arroja una excepción si el origen no contiene elementos. Para que la devolverá un valor por defecto cuando la secuencia de origen está vacío, utilice el método FirstOrDefault

-2

usando Tal Donde() antes de la primera() puede ayudar, ya que mi problema ha sido resuelto en este caso.

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

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

+0

@pwdst usando la condición en la cláusula Where y luego FirstOrDefault sin ninguna expresión lambda. – Elnaz

Cuestiones relacionadas