¿Cómo actualizar registro utilizando Entity Framework 6?

Estoy tratando de actualizar el registro usando EF6. Primero encontrar el registro, si existe, actualizarlo. Aquí está mi código:

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; } } } 

Cada vez que trato de actualizar el registro usando el código anterior, obtengo este error: –

{System.Data.Entity.Infrastructure.DbUpdateConcurrencyException: la actualización, inserción o eliminación de la tienda afectaron a un número inesperado de filas (0). Las entidades pueden haber sido modificadas o eliminadas desde que se cargaron las entidades. Actualizar entrie ObjectStateManager

Está intentando actualizar el registro (que para mí significa “cambiar un valor en un registro existente y guardarlo de nuevo”). Por lo tanto, debe recuperar el objeto, realizar un cambio y guardarlo.

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

He estado revisando el código fuente de Entity Framework y encontré una forma de actualizar realmente una entidad si conoce la propiedad Key, en otro caso debe verificar la implementación de AddOrUpdate:

 public void Update(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); } 

¡Espero que esto ayude!

Puede usar el método AddOrUpdate :

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

Entonces, tiene una entidad que está actualizada y desea actualizarla en la base de datos con la menor cantidad de código … La concurrencia siempre es complicada, pero supongo que solo quiere que sus actualizaciones ganen. Así es como lo hice para mi caso y modifiqué los nombres para imitar tus clases. IOW, simplemente cambie adjuntar para agregar, y funciona para mí:

 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(); } } 

Este código es el resultado de una prueba para actualizar solo un conjunto de columnas sin hacer una consulta para devolver el registro primero. Primero usa el código EF 7.

 //The function receives an object type to receive a custom object can be a view model or an anonymous object wit the properties you will like 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) { //Here is checking if the property is named Id dont add it in the update. It can be refactored to look in the annotations to find a key or to fin in the name any part named id if(ep.Name != "Id") _context.Entry(con).Property(ep.Name).IsModified = true; } } return _context.SaveChanges(); } public static object ToType( object obj, T type) { //create instance of T type object: object tmp = Activator.CreateInstance(Type.GetType(type.ToString())); //loop through the properties of the object you want to covert: foreach (PropertyInfo pi in obj.GetType().GetProperties()) { try { //get the value of 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; } 

Aquí está el código completo:

  public interface IContactRepository { IEnumerable GetAllContats(); IEnumerable GetAllContactsWithAddress(); int Update(object c); } public class ContactRepository : IContactRepository { private ContactContext _context; public ContactRepository(ContactContext context) { _context = context; } public IEnumerable GetAllContats() { return _context.Contacts.OrderBy(c => c.FirstName).ToList(); } public IEnumerable GetAllContactsWithAddress() { return _context.Contacts .Include(c => c.Address) .OrderBy(c => c.FirstName).ToList(); } //TODO Cambiar properties a 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( object obj, T type) { //create instance of T type object: object tmp = Activator.CreateInstance(Type.GetType(type.ToString())); //loop through the properties of the object you want to covert: foreach (PropertyInfo pi in obj.GetType().GetProperties()) { try { //get the value of 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 Address { get; set; } public DbSet Contacts { get; set; } public DbSet 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); } } 

Esta es la mejor solución para este problema: en View, agregue todas las ID (claves). Considere tener múltiples tablas nombradas (Primera, Segunda y Tercera)

 @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) 

En el código 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); } 

Deberías usar el. Método de entrada () en caso de que quiera actualizar todos los campos en su objeto. También tenga en cuenta que no puede cambiar el ID de campo (clave), por lo tanto, primero configure el Id para algunos mientras edita.

 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(); } 

Deberías eliminar db.Books.Attach(book);

 using(var myDb = new MyDbEntities()) { user user = new user(); user.username = "me"; user.email = "me@me.com"; myDb.Users.Add(user); myDb.users.Attach(user); myDb.Entry(user).State = EntityState.Modified;//this is for modiying/update existing entry myDb.SaveChanges(); } 

Aquí está mi método de actualización de entidad posterior a RIA (para el marco de tiempo Ef6):

 public static void UpdateSegment(ISegment data) { if (data == null) throw new ArgumentNullException("The expected Segment data is not here."); var context = GetContext(); var originalData = context.Segments.SingleOrDefault(i => i.SegmentId == data.SegmentId); if (originalData == null) throw new NullReferenceException("The expected original Segment data is not here."); FrameworkTypeUtility.SetProperties(data, originalData); context.SaveChanges(); } 

Tenga en cuenta que FrameworkTypeUtility.SetProperties() es una pequeña función de utilidad que escribí mucho antes de AutoMapper en NuGet:

 public static void SetProperties(TIn input, TOut output, ICollection includedProperties) where TIn : class where TOut : class { if ((input == null) || (output == null)) return; Type inType = input.GetType(); Type outType = output.GetType(); foreach (PropertyInfo info in inType.GetProperties()) { PropertyInfo outfo = ((info != null) && info.CanRead) ? outType.GetProperty(info.Name, info.PropertyType) : null; if (outfo != null && outfo.CanWrite && (outfo.PropertyType.Equals(info.PropertyType))) { if ((includedProperties != null) && includedProperties.Contains(info.Name)) outfo.SetValue(output, info.GetValue(input, null), null); else if (includedProperties == null) outfo.SetValue(output, info.GetValue(input, null), null); } } } 

Como dijo Renat, elimine: db.Books.Attach(book);

Además, cambie su consulta de resultados para usar “AsNoTracking”, porque esta consulta arroja el estado del modelo del marco de la entidad. Piensa que “resultado” es el libro para rastrear ahora y no quieres eso.

 var result = db.Books.AsNoTracking().SingleOrDefault(b => b.BookNumber == bookNumber); 

Intentalo….

UpdateModel (libro);

 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 { UpdateModel(book); db.Books.Attach(book); db.Entry(book).State = EntityState.Modified; db.SaveChanges(); } catch (Exception ex) { throw; } } } 

Encontré una manera que funciona bien.

  var Update = context.UpdateTables.Find(id); Update.Title = title; // Mark as Changed context.Entry(Update).State = System.Data.Entity.EntityState.Modified; context.SaveChanges();