Используйте linq для создания прямого обновления без выбора

Доброго времени суток всем.

Я все еще изучаю LINQ, так что простите меня, если это наивно. Когда вы имеете дело с SQL напрямую, вы можете генерировать команды обновления с условными выражениями без выполнения оператора select.

Когда я работаю с linq, мне кажется, что я следую следующему шаблону:

  1. Выбрать объекты
  2. Изменить сущности
  3. Отправить изменения

Я хочу сделать прямое обновление с использованием linq и отложенного выполнения. Возможно ли, что фактическое выполнение происходит непосредственно в SQL без передачи каких-либо данных клиенту?

DataContext dc = new DataContext

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

dc.SubmitChanges

Таким образом, по сути LINQ имеет всю необходимую информацию БЕЗ использования select для генерации команды обновления. Он запустит SQL:

Update Products Set Count = 0 Where Type = 1

Существует ли в LINQ такое ключевое слово, как "set"?

принятый в настоящее время ответ неверен - можете ли вы выбрать правильный?

laktak 07.10.2015 10:49

Приведенные ниже ответы не разрешают обновления на основе наборов, как я описал, но они интересны.

Spence 08.10.2015 03:03
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
43
2
40 368
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Linq 2 SQL не имеет прямых эквивалентов SQL для вставки / обновления / удаления. В V1 единственные обновления, которые вы можете делать с помощью linq, - это SubmmitChanges в контексте или при откате на sql.

Однако некоторые люди пытались преодолеть это ограничение linq, используя собственные реализации.

Пакетное обновление Linq.

Ура, дружище, это было действительно интересное чтение. Будем надеяться, что кое-что из этого попадет в C# 4 или 5, потому что возможность обновления и удаления пакетами - это единственное, чего действительно не хватает в LINQ.

Spence 15.01.2009 02:40
Ответ принят как подходящий

Нет, ни LINQ, ни LINQ to SQL не имеют возможности обновления на основе наборов.

В LINQ to SQL вы должны запросить объект, который хотите обновить, при необходимости обновить поля / свойства, а затем вызвать SubmitChanges (). Например:

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

Если вы хотите выполнить дозирование:

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

В качестве альтернативы вы можете написать запрос самостоятельно:

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

Это код, который у меня есть, мне было интересно, есть ли у LINQ синтаксис для него. Приветствую вас за ответ, но имеет смысл, чтобы обновления происходили на C#, потому что я думаю, если вы хотите писать SQL, вы должны просто написать sql, как это делает функция команды execute.

Spence 15.01.2009 02:42

Это действительно глупо, в linq to sql должно быть поле обновления

jdelator 09.07.2009 10:20

@PeterRuderman Прилагаемый ниже ответ требует знания fooId. Очень немногие сценарии (и в частности мой) не хотят знать эту информацию, просто переведите обновление на SQL. Ниже будет полезно, если у вас есть другие знания о первичных ключах для обновления. Кроме того, это обновит только одну строку, а не всю таблицу, и не получит увеличения производительности на основе набора.

Spence 30.11.2016 04:54

Платформа PLINQO (http://plinqo.com) использует пакетное обновление LINQ для выполнения обновлений.

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

Это выполнит Update Task Set StatusId = 2 Where Id = 1

Фактически вы можете позволить LINQ-to-SQL генерировать операторы обновления:

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

В вашем Dbml установите UpdateCheck = "Never" для всех свойств.

Это сгенерирует один оператор обновления без предварительного выбора.

Одно предостережение: если вы хотите установить для Name значение null, вам придется инициализировать свой объект foo другим значением, чтобы Linq мог обнаружить изменение:

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

Если вы хотите проверить метку времени при обновлении, вы также можете сделать это:

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

Однако это не совсем так. Круто знать синтаксис присоединения, хотя

Spence 01.12.2010 02:15

Другой способ сделать это: context.Foos.Attach(foo, original: new Foo { FooId = fooId });. Это обновит все свойства, которые не установлены в исходной сущности.

orad 22.11.2016 05:04

Попробуй это :

dbEntities.tblSearchItems
     .Where(t => t.SearchItemId == SearchItemId)
     .ToList()
     .ForEach(t => t.isNew = false);
dbEntities.SaveChanges();

Амит, вызов «ToList» загрузит все элементы из базы данных в память. Foreach работает в памяти, а затем сохраненные изменения распространяют их обратно. Я искал что-то, что могло бы создать оператор SQL «Обновить элементы, где условие», который не загружает ЛЮБЫЕ данные локально.

Spence 16.05.2014 09:40

Используйте этот метод расширения: 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);
}

Чтобы использовать его, убедитесь, что объект entity, который вы передаете методу UpdateOnSubmit, имеет все свойства первичного ключа, установленные для записи, которую вы хотите обновить. Затем этот метод обновит запись оставшимися свойствами объекта entity без предварительного извлечения записи.

После вызова UpdateOnSubmit обязательно позвоните в SubmitChanges(), чтобы изменения вступили в силу.

Спасибо, Орад. Это соответствует ответу laktak, но по-прежнему имеет ту же проблему, что действительно выводит одну строку и знание таблицы. Мой вопрос заключался в том, может ли LINQ в конечном итоге выдать запрос обновления на основе набора для SQL, чего из коробки он не будет.

Spence 30.11.2016 04:55

Привет @Spence, я не думаю, что пакетное обновление set возможно через LINQ, вы можете использовать метод AttachAll, но я думаю, что он все равно будет выполнять отдельные команды UPDATE для каждой строки. Мое решение выполняет прямое обновление без выбора, как в заголовке вопроса, но если ваш конкретный вопрос заключается в том, как выполнить пакетное обновление, принятый ответ правильный.

orad 30.11.2016 22:09

Вы можете использовать библиотеку Расширения Entity Framework, она поддерживает пакетное обновление и пакетное слияние, однако библиотека платная:

PM > Install-Package Z.EntityFramework.Extensions

using Z.EntityFramework.Plus;

...

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

Другие вопросы по теме