2012-03-28 18 views
5

Mi jerarquía de objetos es la siguiente:LINQ - actualizar un campo dentro cláusula where

class Detail 
{ 
    public List<Row> Rows { get; set; } 
} 

class Row 
{ 
    public List<Column> Columns { get; set; } 
} 

class Column 
{ 
    public string Name { get; set; } 
    public bool IsUpdated { get; set; } 
} 

Quiero configurar column.IsUpdated = true donde column.Name = "id". Estoy intentando esto, no funciona.

detail.Rows.ForEach(r => r.Columns.Where(c => c.Name.ToLower().Equals("id")).ToList<Column>().Select(c => c.IsUpdated = true)); 
+0

Los métodos 'LINQ' devuelven' readonly' 'IEnumerable' no deben usarse para cambiar los valores. – gdoron

+0

http://stackoverflow.com/questions/823532/apply-function-to-all-elements-of-collection-through-linq – mellamokb

Respuesta

7

La filosofía de LINQ es no tener efectos secundarios. Es por eso que a propósito no hace que sea fácil para ti hacer esto. Se podía hacerlo ya sea con un clásico

var cols = details.Rows.SelectMany(r => r.Columns) 
         .Where(c => c.Name.ToLower().Equals("id")); 
foreach(var col in cols) { 
    col.IsUpdated = true; 
} 

o utilizando List.ForEach, pero de una manera diferente:

details.Rows.SelectMany(r => r.Columns) 
      .Where(c => c.Name.ToLower().Equals("id")).ToList() 
      .ForEach(c => { c.IsUpdated = true }); 
+0

Hola, John. Entonces, ¿qué haces si hay miles de filas que necesitas actualizar por alguna razón? digamos que el operador hace clic en un botón y luego tiene que actualizar todas las filas que tienen el estado "x" al estado "Y", que es fácil y rápido con SQL normal. ¿derecho? Pero si carga todo en la memoria, tarda una eternidad :(¿debería escribir un StoredProcedure en su lugar? ¿Hay una forma mejor? SQL: update tblData set status = 'y' donde status = 'x' –

0

Usted no debe mutar todos los elementos de una colección con LINQ (aunque se puede hacer, ver this question). Es más simple y más legible que simplemente usar un vainilla foreach.

foreach (var row in detail.Rows) 
    foreach (var col in row.Columns) 
     if (c.Name.ToLower().Equals("id")) 
      c.IsUpdated = true; 
1

LINQ realmente está pensado para datos de consulta de, no cambiar los valores dentro de los datos. Si usted quiere hacer todo un detalle del artículo nuevo, que podría hacer que:

var newDetail = new Detail 
    { 
     Rows = detail.Rows.Select(r => new Row 
              { 
               Columns = r.Columns.Select(c => new Column { Name = c.Name, IsUpdated = c.Name.ToLower() == "id" ? true : c.IsUpdated }).ToList() 
              }) 
          .ToList() 
    }; 

Tenga en cuenta que lo anterior podría ser más limpio, lo más probable, si se ha añadido constructores para sus tipos, también.

Dicho esto, si quiere actualizar en su lugar, como si estuviera mostrando, me acaba de utilizar bucles:

foreach(var row in detail.Rows) 
    foreach(var col in row.Columns) 
     if (col.Name.ToLower() == "id") 
      col.IsUpdated = true; 

me parece que mucho más fácil de seguir, especialmente en este caso.

0

yo sólo tengo que trabajar de esta manera. ¿Es ineficiente? En lugar de. Seleccione lo puse. Cualquiera. Funciona, pero no estoy seguro de si es ineficiente en una gran cantidad de datos. Si es así, puedo ir con una de las respuestas.

detail.Rows.ForEach(r => r.Columns.Where(c => c.Name.ToLower().Equals("id")).ToList<Column>().Any(c => c.IsUpdated = true)); 
+1

No funcionó porque Select() se evalúa holgadamente y Any() es codicioso. De todos modos, esta es una muy mala idea. Los efectos secundarios de las consultas de Linq son * la peor práctica * Ah, y edite su pregunta, no publique respuestas para agregar información. – asawyer

0

Haga una prueba. Esto debería actualizar "IsUpdated" ahora con el mismo concepto que ya intentabas usar.

detail.Rows.ForEach(r => r.Columns.Where(c => c.Name.ToLower().Equals("id")).ToList<Column>().Select(c => {c.IsUpdated = true; return c;})); 
Cuestiones relacionadas