Обновить строку, если она существует еще вставить логику с Entity Framework



есть ли у кого-нибудь предложения по наиболее эффективному способу реализации логики "обновить строку, если она существует, иначе вставить" с помощью Entity Framework?

643   7  

7 ответов:

Если вы работаете с вложенным объектом (объект, загруженный из того же экземпляра контекста), вы можете просто использовать:

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<TEntity>(
    this IDbSet<TEntity> set,
    params TEntity[] entities
)
where TEntity : class

который doc:

добавляет или обновляет объекты по ключу при вызове SaveChanges. Аналог к операции "upsert" из терминологии базы данных. Этот метод может быть полезно при заполнении данных с помощью миграции.


ответ комментарий @Smashing1978, я вставлю соответствующие части из ссылке, предоставленной @Колин

задача AddOrUpdate заключается в том, чтобы убедиться, что вы не создаете дубликаты когда вы сеете данные во время разработки.

во-первых, он выполнит запрос в вашей базе данных в поисках записи где все, что вы предоставили в качестве ключа (первый параметр) соответствует сопоставленное значение столбца (или значения), заданное в AddOrUpdate. Так что это это немного рыхлый гусь для соответствия, но прекрасно подходит для посева данные по времени проектирования.

что еще более важно, если совпадение найдено, то обновление обновит все и обнулить все, что не было в вашем AddOrUpdate.

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

Если вы знаете, что используете один и тот же контекст и не отсоединяете какие-либо сущности, вы можете сделать общую версию следующим образом:

public void InsertOrUpdate<T>(T entity, DbContext db) where T : class
{
    if (db.Entry(entity).State == EntityState.Detached)
        db.Set<T>().Add(entity);

    // If an immediate save is needed, can be slow though
    // if iterating through many entities:
    db.SaveChanges(); 
}

db конечно, может быть поле класса, или метод может быть сделан статическим и расширением, но это основы.

магия происходит при вызове 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 чтобы определить, является ли это новый объект или нет, проверьте ответ Ладислава Мрнка.

ответ Ладислава был близок, но мне пришлось сделать несколько изменений, чтобы заставить это работать в EF6 (база данных-первая). Я расширил свой контекст данных с помощью метода on 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);
      }
  }
[....]

вставить еще обновить оба

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. И вы вручную выберете, какие объекты должны быть удалены, если они больше не существуют.

пример:

допустим, у меня есть

Comments

    Ничего не найдено.