web-dev-qa-db-fra.com

Utilisez linq pour générer une mise à jour directe sans sélectionner

G'day tout le monde.

J'apprends encore LINQ alors pardonnez-moi si c'est naïf. Lorsque vous traitez directement avec SQL, vous pouvez générer des commandes de mise à jour avec des conditions, sans exécuter d'instruction select.

Lorsque je travaille avec linq, il semble que je suive le schéma suivant:

  1. Sélectionner des entités
  2. Modifier des entités
  3. Soumettre des changements

Ce que je veux faire est une mise à jour directe en utilisant linq et une exécution différée. Est-il possible que l'exécution réelle se produise directement sur le SQL sans qu'aucune donnée ne soit transmise au client?

DataContext dc = new DataContext

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

dc.SubmitChanges

Donc, par essence, LINQ a toutes les informations dont il a besoin SANS utiliser un select pour générer une commande de mise à jour. Il lancerait le SQL:

Update Products Set Count = 0 Where Type = 1

Un mot clé tel que "set" existe-t-il dans LINQ?

43
Spence

Non, ni LINQ ni LINQ to SQL ne disposent de fonctionnalités de mise à jour définies. 

Dans LINQ to SQL, vous devez rechercher l'objet que vous souhaitez mettre à jour, mettre à jour les champs/propriétés si nécessaire, puis appeler SubmitChanges (). Par exemple:

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

Si vous souhaitez effectuer un traitement par lots:

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

Alternativement, vous pouvez écrire la requête vous-même:

dc.ExecuteCommand("update Product set Count=0 where Type=1", null);
29
Randolpho

Vous pouvez réellement laisser LINQ-to-SQL générer des instructions de mise à jour:

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

Dans votre Dbml, définissez UpdateCheck = "Jamais" pour toutes les propriétés.

Ceci générera une seule déclaration de mise à jour sans avoir à faire une sélection en premier.

Une mise en garde: si vous voulez pouvoir définir Name sur null, vous devez initialiser votre objet foo avec une valeur différente pour que Linq puisse détecter le changement:

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

Si vous souhaitez vérifier l'horodatage lors de la mise à jour, vous pouvez également le faire:

Foo foo=new Foo { FooId=fooId, Modified=... }; 
// Modified needs to be set to UpdateCheck="Always" in the dbml
45
laktak

Linq 2 SQL n'a pas d'équivalents SQL directs d'insertion, de mise à jour et de suppression. Dans V1, les seules mises à jour que vous pouvez faire avec linq sont considérées comme des modifications submmtives sur le contexte ou si vous vous repliez vers SQL.

Cependant, certaines personnes ont essayé de surmonter cette limitation de linq en utilisant des implémentations personnalisées.

Mise à jour par lots Linq.

3
Pop Catalin

Utilisez cette méthode d'extension: 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);
}

Pour l'utiliser, assurez-vous que l'objet entity que vous passez à la méthode UpdateOnSubmit possède toutes les propriétés de clé primaire définies pour l'enregistrement que vous souhaitez mettre à jour. Cette méthode mettra alors à jour l'enregistrement avec les propriétés restantes de l'objet entity sans extraire d'abord l'enregistrement.

Après avoir appelé UpdateOnSubmit, assurez-vous d’appeler SubmitChanges() pour que les modifications s’appliquent.

0
orad

Vous pouvez utiliser Entity Framework Extensions library, il prend en charge la mise à jour et la fusion par lots, mais la bibliothèque n’est pas libre:

PM> Install-Package Z.EntityFramework.Extensions

using Z.EntityFramework.Plus;

...

dc.Products
    .Where(q => q.Type == 1)
    .Update(q => new Product { Count = 0 });
0
koryakinp