user2837480
user2837480

Reputation: 369

Update a property in a sub list which contains in a list

Hi have a list of object and each object has another list items respectively. I want to update a property in a sub list after checking a condition. I have tried a linq query but it doesn't update the property. Please help me

int priceBookId = 1;
foreach (var store in stores)
{
    store.SelectedBooks.Where(d => d.BookID == priceBookId ).Select(x => {x.IsPriceBook = true; return x; });
}

Each stores has selected book list and each book has its own properties. Here what I want is to update IsPriceBook property when selected book is a pricebook

Upvotes: 0

Views: 2839

Answers (3)

Balah
Balah

Reputation: 2540

Select() does not work because that creates a projection that does nothing until you .ToList() it (then it will perform the update). But that's just using Select in the way it's not intended.

You can try ForEach, which loops through the original list, like this:

int priceBookId = 1;
foreach (var store in stores)
{
    store.SelectedBooks.Where(d => d.BookID == priceBookId).ToList().ForEach(x => x.IsPriceBook = true);
}

That's the quickest solution.

Upvotes: 0

Alexei Levenkov
Alexei Levenkov

Reputation: 100555

The code in the post demonstrates why doing updates of objects in .Select (or other LINQ methods) is bad idea:

  • no one ever expect modification to happen, do not expect result to persist or variations of those two
  • delayed/lazy execution of LINQ queries makes it very hard to see what is happening. Code will work fine while debugging and looking at results then fail while running on its own.

Problem with original code - Where and Select are lazily evaluated and hence nothing requests enumeration of the result no evaluation actually happens. To fix - forcing iteration would work. Use .ToList() or .All(...) as shown in Query and updating a property in a collection using LINQ.

foreach (var store in stores)
{
  store.SelectedBooks
   .Where(d => d.BookID == priceBookId )
   .Select(x => {x.IsPriceBook = true; return 42; }) // return anything
   .ToList(); // force iteration with `ToList`
}

You can even remove outer foreach

stores.SelectMany(r =>r.SelectedBooks)
   .Where(d => d.BookID == priceBookId )
   .All(x => {x.IsPriceBook = true; return true; }); // force iteration with All

Indeed fixing code that way will be consider as "hack" and really you should first select item and that act on them:

foreach (var book in 
     stores.SelectMany(store => store.SelectedBooks)
          .Where(d => d.BookID == priceBookId ))
{
  book.IsPriceBook = true;
}

Upvotes: 1

Nikolai
Nikolai

Reputation: 306

select will create new object with updated properties, so if you make like:

var updatedProperties = store.SelectedBooks.Where(d => d.BookID == priceBookId ).Select(x => {x.IsPriceBook = true; return x; });

you will get the result in updatedProperties variable. in your case. you can update property if you use 2 cycles, something like the following:

foreach (var store in stores)
{
    foreach (var selectedBook in store.SelectedBooks.Where(d => d.BookID == priceBookId))
    {
        selectedBook.IsPriceBook = true;
    }
}

since store.SelectedBooks has reference type, selectedBook.IsPriceBook = true; will update value by reference.

Upvotes: 0

Related Questions