我正在尝试使用EF6更新记录。首先找到记录,如果它存在,则更新。 这是我的代码:

var book = new Model.Book
{
    BookNumber =  _book.BookNumber,
    BookName = _book.BookName,
    BookTitle = _book.BookTitle,
};
using (var db = new MyContextDB())
{
    var result = db.Books.SingleOrDefault(b => b.BookNumber == bookNumber);
    if (result != null)
    {
        try
        {
            db.Books.Attach(book);
            db.Entry(book).State = EntityState.Modified;
            db.SaveChanges();
        }
        catch (Exception ex)
        {
            throw;
        }
    }
}

每次我尝试使用上面的代码更新记录时,我都会得到这个错误:

{System.Data.Entity.Infrastructure。DbUpdateConcurrencyException:存储 更新、插入或删除语句受影响的数量超出预期 自实体以来,实体可能已被修改或删除 被加载。刷新ObjectStateManager条目


当前回答

附加实体会将其跟踪状态设置为Unchanged。要更新现有实体,您所需要做的就是将跟踪状态设置为Modified。根据EF6文档:

如果您知道数据库中已经存在一个实体,但可能已经对其进行了更改,那么您可以告诉上下文附加该实体,并将其状态设置为Modified。例如: var existingBlog =新Blog {BlogId = 1, Name = "ADO. log "。NET Blog"}; 使用(var context = new BloggingContext()) { context.Entry (existingBlog)。State = EntityState.Modified; //多做点工作… context.SaveChanges (); }

其他回答

如果您希望更新对象中的所有字段,则应该使用Entry()方法。 还要记住,您不能更改字段id(键),因此首先将id设置为与您编辑时相同。

using(var context = new ...())
{
    var EditedObj = context
        .Obj
        .Where(x => x. ....)
        .First();

    NewObj.Id = EditedObj.Id; //This is important when we first create an object (NewObj), in which the default Id = 0. We can not change an existing key.

    context.Entry(EditedObj).CurrentValues.SetValues(NewObj);

    context.SaveChanges();
}

这是实体框架6.2.0。

如果你有一个特定的DbSet和一个需要更新或创建的项:

var name = getNameFromService();

var current = _dbContext.Names.Find(name.BusinessSystemId, name.NameNo);
if (current == null)
{
    _dbContext.Names.Add(name);
}
else
{
    _dbContext.Entry(current).CurrentValues.SetValues(name);
}
_dbContext.SaveChanges();

但是,这也可以用于具有单个主键或复合主键的通用DbSet。

var allNames = NameApiService.GetAllNames();
GenericAddOrUpdate(allNames, "BusinessSystemId", "NameNo");

public virtual void GenericAddOrUpdate<T>(IEnumerable<T> values, params string[] keyValues) where T : class
{
    foreach (var value in values)
    {
        try
        {
            var keyList = new List<object>();

            //Get key values from T entity based on keyValues property
            foreach (var keyValue in keyValues)
            {
                var propertyInfo = value.GetType().GetProperty(keyValue);
                var propertyValue = propertyInfo.GetValue(value);
                keyList.Add(propertyValue);
            }

            GenericAddOrUpdateDbSet(keyList, value);
            //Only use this when debugging to catch save exceptions
            //_dbContext.SaveChanges();
        }
        catch
        {
            throw;
        }
    }
    _dbContext.SaveChanges();
}

public virtual void GenericAddOrUpdateDbSet<T>(List<object> keyList, T value) where T : class
{
    //Get a DbSet of T type
    var someDbSet = Set(typeof(T));

    //Check if any value exists with the key values
    var current = someDbSet.Find(keyList.ToArray());
    if (current == null)
    {
        someDbSet.Add(value);
    }
    else
    {
        Entry(current).CurrentValues.SetValues(value);
    }
}

对于。net core

context.Customer.Add(customer);
context.Entry(customer).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
context.SaveChanges();

最简单的方法是这样的。

var book = new Model.Book
{
    BookNumber =  _book.BookNumber,
    BookName = _book.BookName,
    BookTitle = _book.BookTitle,
};
using (var db = new MyContextDB())
{
    var result = db.Books.SingleOrDefault(b => b.BookNumber == bookNumber);
    if (result != null)
    {
        try
        {
            // you can't attach book since it doesn't exist in the database yet
            // attach result instead
            db.Books.Attach(result);
            result = book; // this will update all the fields at once
            db.SaveChanges();
        }
        catch (Exception ex)
        {
            throw;
        }
    }
}

你可以使用AddOrUpdate方法:

db.Books.AddOrUpdate(book); //requires using System.Data.Entity.Migrations;
db.SaveChanges();