2009-04-30 12 views
158

Używając LINQ, jeśli chcę wykonać zapytanie i zwrócić obiekt z zapytania, ale zmienię tylko niektóre właściwości w tym obiekcie, w jaki sposób mogę to zrobić? to bez tworzenia nowego obiektu i ręcznie ustawić każdą właściwość? czy to możliwe?LINQ: Wybierz obiekt i zmień niektóre właściwości bez tworzenia nowego obiektu

Przykład:

var list = from something in someList 
      select x // but change one property 
+6

napisałem metodę rozszerzenia w oparciu o odpowiedzi JaredPar jest poniżej, który pozwala osiągnąć ten używając deklaratywnej składni jak mój przykład. Sprawdź to: http://blog.robvolk.com/2009/05/linq-select-object-but-change-some.html –

+1

@RobVolk, link wydaje się martwy - dostałeś nowy? Oto archiwum - [LINQ: Wybierz obiekt, ale zmień niektóre właściwości bez tworzenia nowego obiektu] (https://web.archive.org/web/20120608052434/http://blog.robvolk.com/2009/05/ linq-select-object-but-change-some.html) – KyleMit

+0

http://blog.robvolk.com/2009/05/linq-select-object-but-change-some.html nie znalezione *** Błąd DNS * ** – Kiquenet

Odpowiedz

278

Nie jestem pewien, co składnia zapytania jest. Ale tutaj jest rozszerzony przykład wyrażenia LINQ.

var query = someList.Select(x => { x.SomeProp = "foo"; return x; }) 

Do tego służy anonimowa metoda vs i wyrażenie. Pozwala to na użycie kilku instrukcji w jednym lambda. Można więc łączyć dwie operacje ustawiania właściwości i zwracania obiektu do tej nieco zwięzłej metody.

+0

Dzięki, twoje rozwiązanie działa ładnie. Jak byś napisał to używając składni zapytania? –

+3

@Rob, Nie łatwo. Składnia tego działania jest ... w najlepszym razie nieczytelna. var query = z niego na liście select ((Func ) (() => {it.x = 42; return it;}))(); – JaredPar

+2

Przy okazji, to nie zadziała w LINQ na SQL, z oczywistych powodów. –

7

Nie jest to możliwe w przypadku standardowych operatorów zapytań - chodzi o zintegrowane zapytania językowe, a nie zintegrowaną aktualizację językową. Ale możesz ukryć aktualizację w metodach rozszerzeń.

public static class UpdateExtension 
{ 
    public static IEnumerable<Car> ChangeColorTo(
     this IEnumerable<Car> cars, Color color) 
    { 
     foreach (Car car in cars) 
     { 
      car.Color = color; 
      yield return car; 
     } 
    } 
} 

Teraz możesz go używać w następujący sposób.

cars.Where(car => car.Color == Color.Blue).ChangeColorTo(Color.Red); 
+0

Fajnie, podoba mi się połączenie. – David

+1

To nie jest tak, że chcesz zaktualizować kolekcję podstawową. Chcemy zaktualizować właściwość kolekcji wyników. –

+1

Well LINQ zastępuje SQL, który oznacza Structured * Query * Language, ale nadal odsłania zdolność 'UPDATE',' DELETE' i 'INSERT'. Nie twierdzę, że semantyka jest tym, co uniemożliwia tę funkcję. – KyleMit

16

Nie powinno być żadnych magii LINQ powstrzymujących cię od robienia tego. Nie używaj projekcji, ale zwróci to anonimowy typ.

User u = UserCollection.FirstOrDefault(u => u.Id == 1); 
u.FirstName = "Bob" 

To będzie modyfikować rzeczywistego obiektu, jak również:

foreach (User u in UserCollection.Where(u => u.Id > 10) 
{ 
    u.Property = SomeValue; 
} 
+0

Podoba mi się to, moje pytanie jest na pierwszym przykładzie, co jeśli jakiś u> 10 nie znajduje się na liście? Dodałem kontrolę zerową i wydaje się działać. Również LHS nazwałem u na v. +1. Bardzo zwięzłe. –

0
var item = (from something in someList 
     select x).firstordefault(); 

dostanie pozycję, a następnie można zrobić item.prop1 = 5; aby zmienić konkretną właściwość.

Czy chcesz uzyskać listę pozycji z bazy danych i czy zmienia ona właściwość prop1 dla każdej pozycji na tej zwróconej liście na określoną wartość? jeśli tak można to zrobić (robię to w VB bo wiedzą lepiej):

dim list = from something in someList select x 
for each item in list 
    item.prop1=5 
next 

(lista będzie zawierać wszystkie elementy wrócił ze zmianami)

+0

Chociaż to zadziała, myślę, że OP pytał, jak napisać instrukcję LINQ bez konieczności pisania pętli 'for each'. – fujiiface

46

Jeśli tylko chcesz zaktualizować właściwość na wszystkich elementach następnie

someList.All(x => { x.SomeProp = "foo"; return true; }) 
+1

W EF (Entity Framework): aby zastąpić właściwość na wszystkich obiektach IEnumerable, zaakceptowana odpowiedź zadziałała dla mnie. Kod roboczy dla mnie: var myList = _db.MyObjects.Where (o => o.MyProp == "bar"). AsEnumerable(). Wybierz (x => {x.SomeProp = "foo", return x;}) ; – firepol

-3
User u = UserCollection.Single(u => u.Id == 1); 
u.FirstName = "Bob" 
+0

Nie trzeba duplikować [istniejących odpowiedzi w tym wątku] (http://stackoverflow.com/a/807848/1366033). Jeśli masz komentarz na temat tej odpowiedzi, możesz ją tam umieścić. – KyleMit

22

wolę ten jeden. Można go łączyć z innymi poleceniami linq.

from item in list 
let xyz = item.PropertyToChange = calcValue() 
select item 
+3

niezbyt ładne rozwiązanie, ale działa dobrze. dzięki. – ericosg

0

Odkąd didn't znaleźć odpowiedź tutaj, które uważam za najlepsze rozwiązanie, tu moja droga

Używanie „Wybierz”, aby zmodyfikować dane jest możliwe, ale tylko z trick. W każdym razie "Wybierz" nie jest do tego stworzone. Po prostu wykonuje modyfikację, gdy jest używana z "ToList", ponieważ Linq nie wykonuje, zanim dane będą potrzebne. W każdym razie najlepszym rozwiązaniem jest użycie "foreach".W poniższym kodzie, można zobaczyć:

class Person 
    { 
     public int Age; 
    } 

    class Program 
    { 
     private static void Main(string[] args) 
     { 
      var persons = new List<Person>(new[] {new Person {Age = 20}, new Person {Age = 22}}); 
      PrintPersons(persons); 

      //this doesn't work: 
      persons.Select(p => 
      { 
       p.Age++; 
       return p; 
      }); 
      PrintPersons(persons); 

      //with "ToList" it works 
      persons.Select(p => 
      { 
       p.Age++; 
       return p; 
      }).ToList(); 
      PrintPersons(persons); 

      //This is the best solution 
      persons.ForEach(p => 
      { 
       p.Age++; 
      }); 
      PrintPersons(persons); 
      Console.ReadLine(); 
     } 

     private static void PrintPersons(List<Person> persons) 
     { 
      Console.WriteLine("================"); 
      foreach (var person in persons) 
      { 
       Console.WriteLine("Age: {0}", person.Age); 
      ; 
      } 
     } 
    } 

Przed „foreach”, można także dokonać wyboru linq ...

+1

Jest to już dobrze uwzględnione w istniejących odpowiedziach. – KyleMit

+0

OK, przepraszam, ale nie w tym wątku ... –

Powiązane problemy