Значение обновления DbContext платформы Entity без запроса и по внешнему ключу

У меня есть метод обновления некоторых таблиц. Для обновления мне нужно сначала получить TestProcess, но мне это не нравится. Как я могу обновить TestProcess без операции select(firstOrDefault), используемой только для операции обновления?

Пример метода:

public void UpdateTestProcess(int id, string updateID)
{
    using (TestEntities context = new TestEntities())
                {
                    TestProcess pr = context.TestProcess.FirstOrDefault(x => x.MyID == id);
                    pr.UpdateID = updateID;             

                    context.TestProcess.Attach(pr);
                    context.ObjectStateManager.ChangeObjectState(pr, EntityState.Modified);
                    context.SaveChanges();
               }
}

person zrabzdn    schedule 02.07.2013    source источник
comment
какие? Чтобы обновить элемент, вам сначала нужно «получить» его, чтобы применить обновления. Почему тебе это не нравится?   -  person Jonesopolis    schedule 02.07.2013
comment
Возможно, потому что это лишний запрос к базе данных   -  person Andrei    schedule 02.07.2013
comment
возможный дубликат Могу ли я обновить объект EF без запрашивать его первым?   -  person Andrei    schedule 02.07.2013


Ответы (3)


TestProcess pr = new TestProcess()
{
    MyID == id,
};

context.Set<TestProcess>().Attach(pr);

pr.UpdateID = updateID;

context.SaveChanges();

Если вы устанавливаете значение по умолчанию для этого типа (например, устанавливаете int на 0), оно не будет восприниматься как изменение, и вам нужно вручную установить состояние.

pr.UpdateID = updateID;
context.Entry(pr).Property(p => p.UpdateID).IsModified = true;

Вы можете поместить такой код в методы расширения, чтобы вы могли делать такие вещи (я оставлю реализацию в качестве упражнения):

Foo entity = this.DbContext.GetEntityForUpdate<Foo>(
    item => item.ID, model.ID
    );

this.DbContext.UpdateProperty(entity, item => item.Name, model.Name);
person user247702    schedule 03.07.2013
comment
Как реализовать ваш пример, если я использовал ObjectContext? - person zrabzdn; 03.07.2013
comment
Зачем вам использовать ObjectContext с EF 5? - person user247702; 03.07.2013
comment
Я не могу помочь вам в этом случае. DbContext уже давно рекомендуется, если позволяет ситуация, вы должны использовать его вместо этого. - person user247702; 03.07.2013
comment
В вашем примере MyID является первичным ключом. Мне нужно обновление не только по первичному ключу, нужно обновление и по внешнему ключу. Если бы я использовал ваш пример с TestProcess pr = new TestProcess() { ForeignKey = id }; и pr.UpdateID = updateID; context.Entry(pr).Property(p => p.UpdateID).IsModified = true; после этого у меня возникает ошибка Store update, insert или delete, затронувшая неожиданное количество строк (0). Объекты могли быть изменены или удалены после загрузки объектов. Обновите запись ObjectStateManager. Могу ли я обновить по внешнему ключу? - person zrabzdn; 05.07.2013
comment
Я не верю, что EF способен выполнить такое обновление без предоставления первичного ключа. - person user247702; 05.07.2013

Вы можете сделать так (у вас, вероятно, должны быть все данные процесса тестирования):

TestProcess pr = new TestProcess();

pr.Id = id;
pr.UpdateID = updateID;

context.Attach(pr);
context.ObjectStateManager.ChangeObjectState(pr, EntityState.Modified);
context.SaveChanges();
person Andrei    schedule 02.07.2013
comment
Это не работа. У меня ошибка: Аргумент 1: невозможно преобразовать из «Процесс» в «System.Data.Objects.DataClasses.IEntityWithKey» - person zrabzdn; 02.07.2013
comment
Я пытаюсь использовать context.AttachTo(TestProcesses, pr); context.ObjectStateManager.ChangeObjectState(pr, EntityState.Modified); context.TestProcesses.MergeOption = MergeOption.OverwriteChanges; контекст.ПринятьВсеИзменения(); Но не сохранять изменения - person zrabzdn; 03.07.2013

Код:

TestProcess testprocess = dbcontext.TestProcesses.Attach(new TestProcess { MyID = id });
tp.UpdateID = updateID;
dbcontext.Entry<TestProcess>(testprocess).Property(tp => tp.UpdateID).IsModified = true;
dbcontext.Configuration.ValidateOnSaveEnabled = false;
dbcontext.SaveChanges();

Результат TSQL:

exec sp_executesql N'UPDATE [dbo].[TestProcesses]
SET [UpdateID] = @0
WHERE ([MyID] = @1)
',N'@0 bigint,@1 bigint',@0=2,@1=1

Примечание:

Строка «IsModified = true» необходима, потому что при создании нового объекта TestProcess (только с заполненным свойством MyID) все остальные свойства имеют значения по умолчанию (0, null и т. д.). Если вы хотите обновить БД со «значением по умолчанию», изменение не будет обнаружено инфраструктурой сущностей, и тогда БД не будет обновлена.

В примере:

testprocess.UpdateID = null;

не будет работать без строки «IsModified = true», так как свойство UpdateID, уже равно null, когда вы создали пустой объект TestProcess, вам нужно сказать EF, что этот столбец должен быть обновлен, и это цель этой строки.

person tecla    schedule 15.06.2017