43

G'day everyone.

I'm still learning LINQ so forgive me if this is naive. When you're dealing with SQL directly, you can generate update commands with conditionals, without running a select statement.

When I work with linq I seem to follow the pattern of:

  1. Select entities
  2. Modify entities
  3. Submit changes

What I want to do is a direct update using linq and deferred execution. Is it possible that the actual execution occurs directly at the SQL without any data being transmitted up to the client?

DataContext dc = new DataContext

var q = from product in dc.Products
        where product.Type = 1
        set product.Count = 0

dc.SubmitChanges

So in essence LINQ has all the information it needs WITHOUT using a select to generate an update command. It would run the SQL:

Update Products Set Count = 0 Where Type = 1

Does a keyword like "set" exist in LINQ?

Spence
  • 28,526
  • 15
  • 68
  • 103

7 Answers7

47

You can actually let LINQ-to-SQL generate update statements:

Foo foo=new Foo { FooId=fooId }; // create obj and set keys
context.Foos.Attach(foo);
foo.Name="test";
context.SubmitChanges();

In your Dbml set UpdateCheck="Never" for all properties.

This will generate a single update statement without having to do a select first.

One caveat: if you want to be able to set Name to null you would have to initialize your foo object to a different value so Linq can detect the change:

Foo foo=new Foo { FooId=fooId, Name="###" };
...
foo.Name=null;

If you want to check for a timestamp while updating you can do this as well:

Foo foo=new Foo { FooId=fooId, Modified=... }; 
// Modified needs to be set to UpdateCheck="Always" in the dbml
laktak
  • 57,064
  • 17
  • 134
  • 164
  • 3
    Its not quite set based though. Its cool to know the attach syntax though – Spence Nov 30 '10 at 23:15
  • 1
    Another way to do this is: `context.Foos.Attach(foo, original: new Foo { FooId = fooId });`. This will update all properties that are not set in original entity. – orad Nov 22 '16 at 02:04
30

No, neither LINQ nor LINQ to SQL has set-based update capabilities.

In LINQ to SQL, you must query for the object you wish to update, update the fields/properties as necessary, then call SubmitChanges(). For example:

var qry = from product in dc.Products where Product.Name=='Foobar' select product;
var item = qry.Single();
item.Count = 0;
dc.SubmitChanges();

If you wish to do batching:

var qry = from product in dc.Products where Product.Type==1 select product;
foreach(var item in qry)
{
  item.Count = 0;
}
dc.SubmitChanges();

Alternatively, you could write the query yourself:

dc.ExecuteCommand("update Product set Count=0 where Type=1", null);
Randolpho
  • 55,384
  • 17
  • 145
  • 179
  • 1
    This is the code I have, I was wondering if LINQ had a syntax for it. Cheers for the answer though, it does make sense to have the updates happening in C# because I guess if you want to write SQL, you should just write sql as the execute command function does. – Spence Jan 14 '09 at 23:42
  • 11
    This is really stupid, linq to sql should have an update field – jdelator Jul 09 '09 at 06:20
  • @PeterRuderman The attach answer below requires knowledge of the fooId. Very few scenarios (and in particular mine) do not want to know this info, simply translate the update against SQL. Below is useful if you have some other knowledge of the primary keys to update against. Also that will only update one row, not the full table and will not gain set based performance increases. – Spence Nov 30 '16 at 01:54
3

The PLINQO (http://plinqo.com) framework is using the LINQ batch update to perform updates

context.Task.Update(t => t.Id == 1, t2 => new Task {StatusId = 2});

This will perform a Update Task Set StatusId = 2 Where Id = 1

Highmastdon
  • 6,960
  • 7
  • 40
  • 68
3

Linq 2 SQL doesn't have direct insert/update/delete equivalents of SQL. In V1 the only updates you can do using linq is thought SubmmitChanges on the context or if you fallback to sql.

However some people have tried to overcome this limitation of linq using custom implementations.

Linq batch update.

Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
Pop Catalin
  • 61,751
  • 23
  • 87
  • 115
  • Cheers mate, that was a really interesting read. Let's hope some of this gets into C# 4 or 5, because the ability to update and delete in batches is about the only thing actually missing from LINQ. – Spence Jan 14 '09 at 23:40
0

Use this extension method: EntityExtensionMethods.cs

public static void UpdateOnSubmit<TEntity>(this Table<TEntity> table, TEntity entity, TEntity original = null)
    where TEntity : class, new()
{
    if (original == null)
    {
        // Create original object with only primary keys set
        original = new TEntity();
        var entityType = typeof(TEntity);
        var dataMembers = table.Context.Mapping.GetMetaType(entityType).DataMembers;
        foreach (var member in dataMembers.Where(m => m.IsPrimaryKey))
        {
            var propValue = entityType.GetProperty(member.Name).GetValue(entity, null);
            entityType.InvokeMember(member.Name, BindingFlags.SetProperty, Type.DefaultBinder,
                original, new[] { propValue });
        }
    }

    // This will update all columns that are not set in 'original' object. For
    // this to work, entity has to have UpdateCheck=Never for all properties except
    // for primary keys. This will update the record without querying it first.
    table.Attach(entity, original);
}

To use it, make sure the entity object that you pass to UpdateOnSubmit method has all the primary key properties set for the record you want to update. This method will then update the record with the remaining properties from the entity object without pulling the record first.

After calling UpdateOnSubmit, make sure to call SubmitChanges() for changes to apply.

orad
  • 15,272
  • 23
  • 77
  • 113
  • Thanks Orad. This is in line with laktak's answer, but still has the same issue that it's really inferring a single row and knowledge of a table. My question was whether LINQ could end up issuing a set based update query to SQL, which out of the box it will not. – Spence Nov 30 '16 at 01:55
  • Hi @Spence, I don't think a batch `set` update is possible via LINQ, you could use `AttachAll` method but I think it will still execute individual UPDATE commands for each row. My solution does direct update without select as in the question title, but if your specific question is how to do batch update, the accepted answer is correct. – orad Nov 30 '16 at 19:09
-1

You can use Entity Framework Extensions library, it supports batch update and batch merge, however the library is not free:

PM > Install-Package Z.EntityFramework.Extensions

using Z.EntityFramework.Plus;

...

dc.Products
    .Where(q => q.Type == 1)
    .Update(q => new Product { Count = 0 });
koryakinp
  • 3,989
  • 6
  • 26
  • 56
-3

Try this :

dbEntities.tblSearchItems
     .Where(t => t.SearchItemId == SearchItemId)
     .ToList()
     .ForEach(t => t.isNew = false);
dbEntities.SaveChanges();
Highmastdon
  • 6,960
  • 7
  • 40
  • 68
amit singh
  • 13
  • 1
  • 5
    Amit, the call to "ToList" will load all the items from the database into memory. The foreach works in memory and then the savechanges propogate them back. I was after something that would produce the SQL statement "Update items where condition", which doesn't load ANY data locally. – Spence May 16 '14 at 05:40