Обновить строку, если она существует в остальной логике вставки с платформой Entity Framework
Есть ли у кого-нибудь предложения по наиболее эффективному способу реализации логики «обновить строку, если она существует в другом месте», используя Entity Framework?
- Entity Framework - добавить свойство навигации вручную
- Круговая ссылка была обнаружена при сериализации объекта типа SubSonic.Schema. DatabaseColumn.
- EntityType не имеет ключевой ошибки
- Сохранение и извлечение изображения (двоичного) из SQL Server с использованием Entity Framework 6
- Отложенное исполнение в Asp.net MVC. Посмотрите очень плохо?
- EF 4.1 code-first: Как заказать свойства навигации при использовании методов Include и / или Select?
- Как вызвать Хранимую процедуру в Entity Framework 6 (Code-First)?
- c #, работающий с Entity Framework на многопоточном сервере
Если вы работаете с прикрепленным объектом (объектом, загруженным из того же экземпляра контекста), вы можете просто использовать:
if (context.ObjectStateManager.GetObjectStateEntry(myEntity).State == EntityState.Detached) { context.MyEntities.AddObject(myEntity); } // Attached object tracks modifications automatically context.SaveChanges();
Если вы можете использовать любые знания о ключе объекта, вы можете использовать что-то вроде этого:
if (myEntity.Id != 0) { context.MyEntities.Attach(myEntity); context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified); } else { context.MyEntities.AddObject(myEntity); } context.SaveChanges();
Если вы не можете определить существование объекта по его идентификатору, вы должны выполнить запрос поиска:
var id = myEntity.Id; if (context.MyEntities.Any(e => e.Id == id)) { context.MyEntities.Attach(myEntity); context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified); } else { context.MyEntities.AddObject(myEntity); } context.SaveChanges();
Начиная с платформы Entity Framework 4.3 существует метод AddOrUpdate
в пространстве имен System.Data.Entity.Migrations
:
public static void AddOrUpdate( this IDbSet set, params TEntity[] entities ) where TEntity : class
который по документу :
Добавляет или обновляет объекты по ключу при вызове SaveChanges. Эквивалент операции «upsert» из базы данных. Этот метод может быть полезен при посеве данных с использованием Migrations.
Чтобы ответить на комментарий от @ Smashing1978 , я вставлю соответствующие части из ссылки, предоставленной @Colin
Задача AddOrUpdate заключается в том, чтобы вы не создавали дубликаты при посеве данных во время разработки.
Во-первых, он выполнит запрос в вашей базе данных, ищущий запись, где все, что вы поставили в качестве ключа (первый параметр), соответствует отображаемому значению столбца (или значениям), указанному в AddOrUpdate. Так что это немного рыхло-гуси для соответствия, но отлично подходит для расчета времени разработки.
Что еще более важно, если совпадение найдено, обновление обновит все и обнуляет любые, которые не были в вашем AddOrUpdate.
Тем не менее, у меня есть ситуация, когда я извлекаю данные из внешней службы и вставляю или обновляю существующие значения с помощью первичного ключа (и мои локальные данные для потребителей доступны только для чтения) – с использованием AddOrUpdate
в производстве более 6 месяцев и до сих пор нет проблем.
Если вы знаете, что используете один и тот же контекст и не отсоединяете какие-либо объекты, вы можете сделать такую общую версию:
public void InsertOrUpdate(T entity, DbContext db) where T : class { if (db.Entry(entity).State == EntityState.Detached) db.Set ().Add(entity); // If an immediate save is needed, can be slow though // if iterating through many entities: db.SaveChanges(); }
Конечно, db
может быть полем classа, или метод может быть сделан статическим и расширением, но это основы.
Ответ Ладислава был близок, но мне пришлось сделать пару модификаций, чтобы заставить его работать в EF6 (сначала в базе данных). Я расширил свой контекст данных с помощью метода AddOrUpdate и пока, похоже, хорошо работает с отдельными объектами:
using System.Data.Entity; [....] public partial class MyDBEntities { public void AddOrUpdate(MyDBEntities ctx, DbSet set, Object obj, long ID) { if (ID != 0) { set.Attach(obj); ctx.Entry(obj).State = EntityState.Modified; } else { set.Add(obj); } } [....]
Магия происходит при вызове SaveChanges()
и зависит от текущего EntityState
. Если объект имеет EntityState.Added
, он будет добавлен в базу данных, если он имеет EntityState.Modified
, он будет обновлен в базе данных. Таким образом, вы можете реализовать метод InsertOrUpdate()
следующим образом:
public void InsertOrUpdate(Blog blog) { using (var context = new BloggingContext()) { context.Entry(blog).State = blog.BlogId == 0 ? EntityState.Added : EntityState.Modified; context.SaveChanges(); } }
Подробнее о EntityState
Если вы не можете проверить Id = 0
чтобы определить, является ли это новой сущностью или нет, проверьте ответ Ladislav Mrnka .
Вставьте еще обновление
public void InsertUpdateData() { //Here TestEntities is the class which is given from "Save entity connection setting in web.config" TestEntities context = new TestEntities(); var query = from data in context.Employee orderby data.name select data; foreach (Employee details in query) { if (details.id == 1) { //Assign the new values to name whose id is 1 details.name = "Sanjay"; details. Surname="Desai"; details.address=" Desiwadi"; } else if(query==null) { details.name="Sharad"; details.surname=" Chougale "; details.address=" Gargoti"; } //Save the changes back to database. context.SaveChanges(); }
На мой взгляд, стоит сказать, что с недавно выпущенным EntityGraphOperations для Entity Framework Code First вы можете спасти себя от написания повторяющихся кодов для определения состояний всех объектов на графике. Я являюсь автором этого продукта. И я опубликовал его в github , code-project ( включает пошаговую демонстрацию и образец проекта готов к загрузке) и nuget .
Он автоматически установит состояние объектов для Added
или Modified
. И вы вручную выберете, какие сущности должны быть удалены, если они больше не существуют.
Пример:
Допустим, у меня есть объект Person
. Person
может быть много телефонов, Документ и может иметь супруга.
public class Person { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string MiddleName { get; set; } public int Age { get; set; } public int DocumentId {get; set;} public virtual ICollection Phones { get; set; } public virtual Document Document { get; set; } public virtual PersonSpouse PersonSpouse { get; set; } }
Я хочу определить состояние всех объектов, которые включены в график.
context.InsertOrUpdateGraph(person) .After(entity => { // Delete missing phones. entity.HasCollection(p => p.Phones) .DeleteMissingEntities(); // Delete if spouse is not exist anymore. entity.HasNavigationalProperty(m => m.PersonSpouse) .DeleteIfNull(); });
Также, как вы знаете, уникальные ключевые свойства могут играть роль при определении состояния объекта Phone. Для таких специальных целей у нас есть class ExtendedEntityTypeConfiguration<>
, который наследуется от EntityTypeConfiguration<>
. Если мы хотим использовать такие специальные конфигурации, мы должны наследовать наши classы сопоставления из ExtendedEntityTypeConfiguration<>
, а не EntityTypeConfiguration<>
. Например:
public class PhoneMap: ExtendedEntityTypeConfiguration { public PhoneMap() { // Primary Key this.HasKey(m => m.Id); … // Unique keys this.HasUniqueKey(m => new { m.Prefix, m.Digits }); } }
Это все.