Chcę zmienić niektóre właściwości obiektu wynikowego zapytania LINQ bez tworzenia nowego obiektu i ręcznego ustawiania każdej właściwości. czy to możliwe?
Przykład:
var list = from something in someList
select x // but change one property
Chcę zmienić niektóre właściwości obiektu wynikowego zapytania LINQ bez tworzenia nowego obiektu i ręcznego ustawiania każdej właściwości. czy to możliwe?
Przykład:
var list = from something in someList
select x // but change one property
Odpowiedzi:
Nie jestem pewien, jaka jest składnia zapytania. Ale oto przykład rozszerzonego wyrażenia LINQ.
var query = someList.Select(x => { x.SomeProp = "foo"; return x; })
To robi to użyć anonimowej metody vs i wyrażenia. Pozwala to na użycie kilku instrukcji w jednej lambda. Możesz więc połączyć dwie operacje ustawiania właściwości i zwracania obiektu do tej nieco zwięzłej metody.
ToList()przed tym wydaje się załatwić sprawę. Nie jestem pewien, dlaczego to dostajesz. Jeśli jest to Entity Framework, to też z tym nie działa.
Jeśli chcesz po prostu zaktualizować właściwość we wszystkich elementach, to
someList.All(x => { x.SomeProp = "foo"; return true; })
Wolę tą. Można go łączyć z innymi poleceniami linq.
from item in list
let xyz = item.PropertyToChange = calcValue()
select item
Nie powinna istnieć żadna magia LINQ powstrzymująca cię przed zrobieniem tego. Nie używaj jednak projekcji, która zwróci anonimowy typ.
User u = UserCollection.FirstOrDefault(u => u.Id == 1);
u.FirstName = "Bob"
To zmodyfikuje prawdziwy obiekt, a także:
foreach (User u in UserCollection.Where(u => u.Id > 10)
{
u.Property = SomeValue;
}
Nie jest to możliwe w przypadku standardowych operatorów zapytań - jest to Zapytanie zintegrowane z językiem, a nie Aktualizacja zintegrowana z językiem. Ale możesz ukryć swoją aktualizację w metodach rozszerzenia.
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);
UPDATE, DELETEi INSERT. Nie argumentowałbym więc, że semantyka jest tym, co zapobiega tej funkcji.
Jeśli chcesz zaktualizować elementy za pomocą Whereklauzuli, użycie .Where (...) obetnie wyniki, jeśli:
mylist = mylist.Where(n => n.Id == ID).Select(n => { n.Property = ""; return n; }).ToList();
Możesz dokonywać aktualizacji określonych pozycji na liście w następujący sposób:
mylist = mylist.Select(n => { if (n.Id == ID) { n.Property = ""; } return n; }).ToList();
Zawsze zwracaj przedmiot, nawet jeśli nie dokonasz żadnych zmian. W ten sposób będzie on przechowywany na liście.
Często spotykamy się z tym, że chcemy dołączyć wartość indeksu oraz pierwszy i ostatni wskaźnik do listy bez tworzenia nowego obiektu. To pozwala poznać pozycję elementu na liście, wyliczenie itp. Bez konieczności modyfikowania istniejącej klasy, a następnie wiedzieć, czy jesteś na pierwszym elemencie na liście, czy na ostatnim.
foreach (Item item in this.Items
.Select((x, i) => {
x.ListIndex = i;
x.IsFirst = i == 0;
x.IsLast = i == this.Items.Count-1;
return x;
}))
Możesz po prostu rozszerzyć dowolną klasę, używając:
public abstract class IteratorExtender {
public int ListIndex { get; set; }
public bool IsFirst { get; set; }
public bool IsLast { get; set; }
}
public class Item : IteratorExtender {}
Ponieważ nie znalazłem tutaj odpowiedzi, którą uważam za najlepsze rozwiązanie, oto moja droga:
Używanie „Wybierz” do modyfikowania danych jest możliwe, ale z pewną sztuczką. W każdym razie „Select” nie jest do tego stworzony. Po prostu wykonuje modyfikację, gdy jest używana z „ToList”, ponieważ Linq nie wykonuje się przed potrzebą danych. W każdym razie najlepszym rozwiązaniem jest użycie „foreach”. W poniższym kodzie widać:
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żesz również dokonać wyboru linq ...
var item = (from something in someList
select x).firstordefault();
Otrzymałbym item, a następnie możesz zrobić, item.prop1=5;aby zmienić konkretną właściwość.
A może chcesz uzyskać listę elementów z bazy danych i zmienić tę właściwość prop1dla każdego elementu na tej zwróconej liście na określoną wartość? Jeśli tak, możesz to zrobić (robię to w VB, ponieważ wiem to lepiej):
dim list = from something in someList select x
for each item in list
item.prop1=5
next
( listbędzie zawierać wszystkie elementy zwrócone z Twoimi zmianami)
for eachpętli.
W 2020 roku korzystam z tej MoreLinq Pipemetody. https://morelinq.github.io/2.3/ref/api/html/M_MoreLinq_MoreEnumerable_Pipe__1.htm
User u = UserCollection.Single(u => u.Id == 1);
u.FirstName = "Bob"