如何使用Entity Framework 6更新记录?

use*_*064 227 c# entity-framework ef-database-first entity-framework-6

我正在尝试使用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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

每次我尝试使用上面的代码更新记录时,我收到此错误: -

{System.Data.Entity.Infrastructure.DbUpdateConcurrencyException:存储更新,插入或删除语句影响了意外的行数(0).自实体加载后,实体可能已被修改或删除.刷新ObjectStateManager entrie

Cra*_* W. 316

您正在尝试更新记录(对我而言,这意味着"更改现有记录上的值并将其保存回来").因此,您需要检索对象,进行更改并保存.

using (var db = new MyContextDB())
{
    var result = db.Books.SingleOrDefault(b => b.BookNumber == bookNumber);
    if (result != null)
    {
        result.SomeValue = "Some new value";
        db.SaveChanges();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 分配值不会更新数据库,在上下文中使用修改后的对象调用`db.SaveChanges()`会更新数据库. (14认同)
  • 它仍然令我着迷...所以var结果,实际上变得连接到dbcontext ...所以这意味着任何dbcontext成员实例化的任何变量实际上都会将该关联关联到数据库,以便对该变量应用任何更改,它也适用或坚持? (6认同)
  • 您不必首先检索对象以便更新它.我遇到了同样的问题,直到我意识到我正在尝试更改其中一个主键值(复合键).只要提供正确的主键,就可以将EntityState设置为Modified,并且SaveChanges()将起作用,前提是您不要破坏表中定义的其他完整性约束. (6认同)
  • 因为上下文生成了对象,所以上下文可以跟踪对象,包括对对象的更改.当您调用`SaveChanges`时,上下文会评估它正在跟踪的所有对象,以确定它们是否已添加,更改或删除,并向连接的数据库发出相应的SQL. (5认同)
  • 我面临同样的问题 - 使用EF6,尝试更新实体.Attach + EntityState.Modified不起作用.只有工作是 - 您需要检索对象,进行所需的更改,并通过db.SaveChanges()保存它; (3认同)
  • W,这究竟是如何运作的?如何将值赋予"结果",实际更新数据库? (2认同)
  • 这个查询是否相同?,`var result = db.Books.Where(b => b.BookNumber == bookNumber).SingleOrDefault();`有没有[性能](http://stackoverflow.com/a/1745709/2218697)考虑在`FirstOrDefault`和`SingleOrDefault`之间? (2认同)
  • @stom:是的,查询是相同的,因为它将返回相同的结果.您必须对其进行测试,以确定您的具体情况是否存在性能差异. (2认同)

Mig*_*uel 141

我一直在审查实体框架的源代码,如果你知道Key属性,在其他情况下你需要检查AddOrUpdate实现,我找到了实际更新实体的方法:

public void Update<T>(T item) where T: Entity
{
    // assume Entity base class have an Id property for all items
    var entity = _collection.Find(item.Id);
    if (entity == null)
    {
        return;
    }

    _context.Entry(entity).CurrentValues.SetValues(item);
}
Run Code Online (Sandbox Code Playgroud)

希望这有帮助!

  • 太好了!无需枚举所有属性.我假设在设置值后需要调用`SaveChanges()`. (9认同)
  • 这向我抱怨我正在尝试编辑ID字段 (6认同)
  • 是的,更改将保留在SaveChanges()上 (2认同)
  • @VasilyHall - 如果ID字段(或任何已定义主键的字段)在模型之间不同(包括其中一个模型中的null/0),则会发生这种情况.确保两个模型之间的ID匹配,它会更新. (2认同)

nic*_*v80 47

您可以使用以下AddOrUpdate方法:

db.Books.AddOrUpdate(book); //requires using System.Data.Entity.Migrations;
db.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

  • 在数据库迁移期间使用`.AddOrUpdate()`,强烈建议不要在迁移之外使用此方法,因此为什么它在`Entity.Migrations`命名空间中. (95认同)
  • 除非您知道自己在做什么,否则请不要使用它!阅读:https://www.michaelgmccarthy.com/2016/08/24/entity-framework-addorupdate-is-a-destructive-operation/ (3认同)
  • 我今天再次回到这个问题上,我可以警告大家这不是*理想使用案例的好解决方案 (3认同)
  • 正如@AdamVincent 所说,`AddOrUpdate()` 方法用于迁移,不适合只需要更新现有行的情况。如果您没有带有搜索参考(即 ID)的书,它会创建新行,并且在出现的情况下可能会出现问题(例如,如果您有一个 API,它需要返回 404-NotFound 响应)尝试为不存在的行调用 PUT 方法)。 (2认同)

小智 19

因此,您有一个已更新的实体,并且您希望使用最少量的代码在数据库中更新它...

并发总是很棘手,但我假设你只是希望你的更新获胜.这是我为同一个案例做的事情,并修改名称来模仿你的类.换句话说,只需attach改为add,它对我有用:

public static void SaveBook(Model.Book myBook)
{
    using (var ctx = new BookDBContext())
    {
        ctx.Books.Add(myBook);
        ctx.Entry(myBook).State = System.Data.Entity.EntityState.Modified;
        ctx.SaveChanges();
    }
}
Run Code Online (Sandbox Code Playgroud)


Bon*_*lin 13

Attaching 一个实体会将其跟踪状态设置为Unchanged。要更新现有实体,您只需将跟踪状态设置为Modified。根据EF6 文档

如果您知道某个实体已存在于数据库中,但可能已对其进行了更改,那么您可以告诉上下文附加该实体并将其状态设置为已修改。例如:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Entry(existingBlog).State = EntityState.Modified;

    // Do some more work...  

    context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)


Jua*_*uan 9

此代码是测试的结果,该测试仅更新一组列而不进行查询以首先返回记录.它首先使用Entity Framework 7代码.

// This function receives an object type that can be a view model or an anonymous 
// object with the properties you want to change. 
// This is part of a repository for a Contacts object.

public int Update(object entity)
{
    var entityProperties =  entity.GetType().GetProperties();   
    Contacts con = ToType(entity, typeof(Contacts)) as Contacts;

    if (con != null)
    {
        _context.Entry(con).State = EntityState.Modified;
        _context.Contacts.Attach(con);

        foreach (var ep in entityProperties)
        {
            // If the property is named Id, don't add it in the update. 
            // It can be refactored to look in the annotations for a key 
            // or any part named Id.

            if(ep.Name != "Id")
                _context.Entry(con).Property(ep.Name).IsModified = true;
        }
    }

    return _context.SaveChanges();
}

public static object ToType<T>(object obj, T type)
{
    // Create an instance of T type object
    object tmp = Activator.CreateInstance(Type.GetType(type.ToString()));

    // Loop through the properties of the object you want to convert
    foreach (PropertyInfo pi in obj.GetType().GetProperties())
    {
        try
        {
            // Get the value of the property and try to assign it to the property of T type object
            tmp.GetType().GetProperty(pi.Name).SetValue(tmp, pi.GetValue(obj, null), null);
        }
        catch (Exception ex)
        {
            // Logging.Log.Error(ex);
        }
    }
    // Return the T type object:         
    return tmp;
}
Run Code Online (Sandbox Code Playgroud)

这是完整的代码:

public interface IContactRepository
{
    IEnumerable<Contacts> GetAllContats();
    IEnumerable<Contacts> GetAllContactsWithAddress();
    int Update(object c);
}

public class ContactRepository : IContactRepository
{
    private ContactContext _context;

    public ContactRepository(ContactContext context)
    {
        _context = context;
    }

    public IEnumerable<Contacts> GetAllContats()
    {
        return _context.Contacts.OrderBy(c => c.FirstName).ToList();
    }

    public IEnumerable<Contacts> GetAllContactsWithAddress()
    {
        return _context.Contacts
            .Include(c => c.Address)
            .OrderBy(c => c.FirstName).ToList();
    }   

    //TODO Change properties to lambda expression
    public int Update(object entity)
    {
        var entityProperties = entity.GetType().GetProperties();

        Contacts con = ToType(entity, typeof(Contacts)) as Contacts;

        if (con != null)
        {
            _context.Entry(con).State = EntityState.Modified;
            _context.Contacts.Attach(con);

            foreach (var ep in entityProperties)
            {
                if(ep.Name != "Id")
                    _context.Entry(con).Property(ep.Name).IsModified = true;
            }
        }

        return _context.SaveChanges();
    }

    public static object ToType<T>(object obj, T type)
    {
        // Create an instance of T type object
        object tmp = Activator.CreateInstance(Type.GetType(type.ToString()));

        // Loop through the properties of the object you want to convert
        foreach (PropertyInfo pi in obj.GetType().GetProperties())
        {
            try
            {
                // Get the value of the property and try to assign it to the property of T type object
                tmp.GetType().GetProperty(pi.Name).SetValue(tmp, pi.GetValue(obj, null), null);
            }
            catch (Exception ex)
            {
                // Logging.Log.Error(ex);
            }
        }
        // Return the T type object
        return tmp;
    }
}    

public class Contacts
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Company { get; set; }
    public string Title { get; set; }
    public Addresses Address { get; set; }    
}

public class Addresses
{
    [Key]
    public int Id { get; set; }
    public string AddressType { get; set; }
    public string StreetAddress { get; set; }
    public string City { get; set; }
    public State State { get; set; }
    public string PostalCode { get; set; }  
}

public class ContactContext : DbContext
{
    public DbSet<Addresses> Address { get; set; } 
    public DbSet<Contacts> Contacts { get; set; } 
    public DbSet<State> States { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        var connString = "Server=YourServer;Database=ContactsDb;Trusted_Connection=True;MultipleActiveResultSets=true;";
        optionsBuilder.UseSqlServer(connString);
        base.OnConfiguring(optionsBuilder);
    }
}
Run Code Online (Sandbox Code Playgroud)


Jar*_*rek 8

你应该使用.如果要更新对象中的所有字段,请使用Entry()方法.另请注意,您无法更改字段ID(键),因此在编辑时首先将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();
}
Run Code Online (Sandbox Code Playgroud)

  • 你应该至少尝试回答这个问题,而不仅仅是发布代码 (2认同)

Far*_*han 8

我找到了一种效果很好的方法。

 var Update = context.UpdateTables.Find(id);
        Update.Title = title;

        // Mark as Changed
        context.Entry(Update).State = System.Data.Entity.EntityState.Modified;
        context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)


Chr*_*ete 7

对于.net core

context.Customer.Add(customer);
context.Entry(customer).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)


小智 5

以下是此问题的最佳解决方案:在视图中添加所有ID(密钥).考虑有多个名为(第一,第二和第三)的表

@Html.HiddenFor(model=>model.FirstID)
@Html.HiddenFor(model=>model.SecondID)
@Html.HiddenFor(model=>model.Second.SecondID)
@Html.HiddenFor(model=>model.Second.ThirdID)
@Html.HiddenFor(model=>model.Second.Third.ThirdID)
Run Code Online (Sandbox Code Playgroud)

在C#代码中,

[HttpPost]
public ActionResult Edit(First first)
{
  if (ModelState.Isvalid)
  {
    if (first.FirstID > 0)
    {
      datacontext.Entry(first).State = EntityState.Modified;
      datacontext.Entry(first.Second).State = EntityState.Modified;
      datacontext.Entry(first.Second.Third).State = EntityState.Modified;
    }
    else
    {
      datacontext.First.Add(first);
    }
    datacontext.SaveChanges();
    Return RedirectToAction("Index");
  }

 return View(first);
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

477560 次

最近记录:

6 年,11 月 前