105

Table:

id     userid  friendid   name    status
1      1        2         venkat  false
2      1        3         sai     true
3      1        4         arun    false
4      1        5         arjun   false

If a user sends userid=1,friendids=2,4,5 status=true

How would I write the query to update the above? All friendids status is true. [2,3,4 at a time]?

Draken
  • 3,134
  • 13
  • 34
  • 54
user1237131
  • 1,853
  • 3
  • 26
  • 35

3 Answers3

261

To update one column here are some syntax options:

Option 1

var ls=new int[]{2,3,4};
using (var db=new SomeDatabaseContext())
{
    var some= db.SomeTable.Where(x=>ls.Contains(x.friendid)).ToList();
    some.ForEach(a=>a.status=true);
    db.SubmitChanges();
}

Option 2

using (var db=new SomeDatabaseContext())
{
     db.SomeTable
       .Where(x=>ls.Contains(x.friendid))
       .ToList()
       .ForEach(a=>a.status=true);

     db.SubmitChanges();
}

Option 3

using (var db=new SomeDatabaseContext())
{
    foreach (var some in db.SomeTable.Where(x=>ls.Contains(x.friendid)).ToList())
    {
        some.status=true;
    }
    db.SubmitChanges();
}

Update

As requested in the comment it might make sense to show how to update multiple columns. So let's say for the purpose of this exercise that we want not just to update the status at ones. We want to update name and status where the friendid is matching. Here are some syntax options for that:

Option 1

var ls=new int[]{2,3,4};
var name="Foo";
using (var db=new SomeDatabaseContext())
{
    var some= db.SomeTable.Where(x=>ls.Contains(x.friendid)).ToList();
    some.ForEach(a=>
                    {
                        a.status=true;
                        a.name=name;
                    }
                );
    db.SubmitChanges();
}

Option 2

using (var db=new SomeDatabaseContext())
{
    db.SomeTable
        .Where(x=>ls.Contains(x.friendid))
        .ToList()
        .ForEach(a=>
                    {
                        a.status=true;
                        a.name=name;
                    }
                );
    db.SubmitChanges();
}

Option 3

using (var db=new SomeDatabaseContext())
{
    foreach (var some in db.SomeTable.Where(x=>ls.Contains(x.friendid)).ToList())
    {
        some.status=true;
        some.name=name;
    }
    db.SubmitChanges();
}

Update 2

In the answer I was using LINQ to SQL and in that case to commit to the database the usage is:

db.SubmitChanges();

But for Entity Framework to commit the changes it is:

db.SaveChanges()
Paul Zahra
  • 9,522
  • 8
  • 54
  • 76
Arion
  • 31,011
  • 10
  • 70
  • 88
  • 6
    And for multiple comments you need to do: `records.ForEach(x=> { x.Deleted = true; x.DeletedByUserID = deletedByUserId; x.DeletedOn = DateTime.Now; });` – JonH Sep 12 '14 at 11:35
  • @Jonh what has that to do with the question that the OP has? – Arion Sep 12 '14 at 18:13
  • Arion simple answer...someone googles how to do this and this answer is tops on google. The answer is correct however the person googling wants to do this for multiple columns not just one. My comment fills that missing piece nothing more just an fyi... – JonH Sep 12 '14 at 21:34
  • @Jonh : That is a valid point and I will update the answer for updating multiple columns. I was just a little bit confused because you comment said "And for multiple comments" not "And for multiple columns". Thank you for the feedback – Arion Sep 13 '14 at 09:01
  • @JonH : I update the answer. Is that what you meant? Or do you want me to expand more? – Arion Sep 16 '14 at 07:47
  • 2
    Shouldn't it be `db.SaveChanges()` and not `db.SubmitChanges()`? – bradlis7 Dec 02 '14 at 15:54
  • Ah, ok. No biggie, I just thought it was invalid when I saw it. – bradlis7 Dec 03 '14 at 15:45
  • 3
    ...All three of your options are the same. In fact the only difference between the first two is that one uses a variable and one doesn't. Having both is just increased noise. – BlueRaja - Danny Pflughoeft Apr 04 '15 at 03:44
  • 2
    Note: This will generate a separate SQL Update Query *per* Row. In this case it's not, but *if* the # Rows are "significant" (i.e. mil's, k's even 100's), you may want to use a single SQL Update Query via embedded SQL or Stored Proc instead. Source: "https://social.msdn.microsoft.com/Forums/en-US/0f014318-5259-43c7-8518-06948cec465e/updating-multiple-rows-using-linq?forum=linqprojectgeneral" – Tom Jul 08 '16 at 19:51
  • Just adding a comment that ForEach is no longer part of Linq. See question 10299458. – Johncl Sep 27 '16 at 11:51
  • 3
    is it possible to do without `ToList()`? It's a killer – Toolkit Jan 13 '17 at 16:27
  • 1
    @Toolkit `ToList()` just forces enumeration of the current `IQueryable` or `IEnumerable`. You **have** to eventually enumerate *something* to do any work at all. So if you found it is killing performance, you're doing it at the wrong juncture--when, for example, it might end up enumerating every row in the database because you haven't supplied the proper conditions. It honestly is NOT the issue. But yes, this will generate a separate update for every row, so it's not going to perform well for tens of thousands of them... – ErikE Feb 26 '17 at 22:50
  • 2
    Does ToList() gets all the records from the database, according to the condition, doesn't it? If that's right, it would be really bad performance, What if there are millions of records, we load them into the memory to operate this function? Please correct me if I'm mistaken. – Jacob Mar 07 '17 at 11:11
  • @IgorLevashov https://stackoverflow.com/questions/48520849/linq-query-foreach-cannot-use – HoGo Apr 03 '19 at 09:04
  • In VB (Don't forgett use Sub, not Function): `some.ForEach(Sub(x) x.status= False)` – Dani Apr 11 '19 at 11:48
28

Do not use the ToList() method as in the accepted answer !

Running SQL profiler, I verified and found that ToList() function gets all the records from the database. It is really bad performance !!

I would have run this query by pure sql command as follows:

string query = "Update YourTable Set ... Where ...";    
context.Database.ExecuteSqlCommandAsync(query, new SqlParameter("@ColumnY", value1), new SqlParameter("@ColumnZ", value2));

This would operate the update in one-shot without selecting even one row.

Jacob
  • 3,598
  • 4
  • 35
  • 56
  • 1
    While I agree with you, the question does specifically ask for linq way. And, you don't actually need to use `.ToList()`. I do believe you can use a `.ForEachAsync()` method or `foreach` regular loop without `.ToList()`. Still probably not great performance wise. But, you shouldn't be using EF if you're that concerned with performance IMO. – Santiago Jan 28 '21 at 21:26
5

This is what I did:

EF:

using (var context = new SomeDBContext())
{
    foreach (var item in model.ShopItems)  // ShopItems is a posted list with values 
    {    
        var feature = context.Shop
                             .Where(h => h.ShopID == 123 && h.Type == item.Type).ToList();

        feature.ForEach(a => a.SortOrder = item.SortOrder);
    }

    context.SaveChanges();
}

Hope helps someone.

Note: 5 years later, As said in comments its not good option because i am making DB calls to get some data inside foreach. If you are not doing the same then its ok to use.

Shaiju T
  • 6,201
  • 20
  • 104
  • 196
  • Works like a charm! – yu yang Jian Jul 28 '17 at 07:27
  • 5
    this is bad, you are calling database each time to fetch the record `feature` and also you should not add `context.SaveChanges()` inside `foreach` it should be outside foreach loop. – Jawand Singh Nov 03 '17 at 09:43
  • 1
    The SQL is not the same as the EF code. In SQL it is just 1 command that runs on all rows and update the table. The EF code takes all rows first, updates the changed ones on DB, meaning that if you have 1000 updated rows, it will execute 1000 sql updates – Ashkan S Jan 15 '18 at 11:24
  • 1
    @stom It is not still the same :) context.SaveChanges(); just submits your update. there will still be 1000 update commands each using the id and not the SortOrder condition – Ashkan S Mar 06 '18 at 14:44
  • @AshkanSirous , ok :) In accepted answer option 3 does the same. I don't thing as of now there is another solution in `EF`. Else we have to try `ADO.NET`. – Shaiju T Mar 07 '18 at 04:32
  • 2
    @stom ExecuteSqlCommand exists on EF for this purpose but on I agree it is not pretty :) Anyways, my point was that you've written a SQL command and a different EF-C# code and claiming that they are equal. :) – Ashkan S Mar 07 '18 at 13:56