2012-03-28 7 views
5

Ma hiérarchie d'objets est comme ceci:LINQ - mettre à jour un champ dans la clause 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; } 
} 

Je veux mettre column.IsUpdated = true où column.Name = "id". J'essaie ça, ça ne marche pas.

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

Les méthodes 'LINQ' renvoient un' readonly' 'IEnumerable' qui ne devrait pas être utilisé pour modifier des valeurs. – gdoron

+0

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

Répondre

7

La philosophie de LINQ est de ne pas avoir d'effets secondaires. C'est pourquoi, intentionnellement, cela ne vous facilite pas la tâche. Vous pouvez le faire soit avec un

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

ou en utilisant List.ForEach, mais d'une autre manière classique:

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

Hey John. Alors que faites-vous s'il y a des milliers de lignes que vous avez besoin de mettre à jour pour une raison quelconque? disons que l'opérateur clique sur un bouton et que vous devez mettre à jour toutes les lignes qui ont le statut "x" au statut "Y" qui est facile et rapide par le SQL normal. droite? Mais si vous chargez tout en mémoire, cela prend une éternité :(devrais-je écrire un StoredProcedure à la place? SQL: mise à jour tblData set status = 'y' où status = 'x' –

0

Vous ne devriez pas muter tous les éléments d'une collection avec LINQ (bien qu'il puisse être fait, voir this question). Il est plus simple et plus lisible d'utiliser simplement une vanille foreach.

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

LINQ est vraiment destiné à les données d'interrogation, ne pas modifier les valeurs dans les données. Si vous voulez faire un élément nouveau ensemble de détails, vous pouvez le faire:

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

Notez que le ci-dessus serait plus propre, le plus probable, si vous avez ajouté des constructeurs pour vos types, aussi bien.

Cela étant dit, si vous voulez le mettre à jour en place, comme vous montriez, je voudrais simplement utiliser des boucles:

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

Je trouve que beaucoup plus facile à suivre, en particulier dans ce cas.

0

Je viens de recevoir ça fonctionne comme ça. Est-ce inefficace? Au lieu de .Sélectionner je mets .Tout. Cela fonctionne, mais je ne suis pas sûr que ce soit inefficace sur une grande quantité de données. Si oui, je peux aller avec l'une des réponses.

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

Cela n'a pas fonctionné parce que Select() est évalué paresseusement, et Any() est gourmand.C'est vraiment une très mauvaise idée.Les effets secondaires de Linq Queries sont * pire pratique * Oh, et éditer votre question, ne postez pas de réponses pour ajouter des informations. – asawyer

0

Faites un essai. Cela devrait mettre à jour "IsUpdated" maintenant avec le même concept que vous essayiez déjà d'utiliser.

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