update registro mvc multiple insertar from framework first code c# entity-framework entity-framework-6 ef-database-first

c# - mvc - ¿Cómo actualizar el registro con Entity Framework 6?



update multiple rows entity framework (17)

Estoy tratando de actualizar el registro usando EF6. Primero encuentre el registro, si existe, actualícelo. 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 intento actualizar el registro con el código anterior, recibo este error: -

{System.Data.Entity.Infrastructure.DbUpdateConcurrencyException: la declaración de actualización, inserción o eliminación del almacén afectó un número inesperado de filas (0). Las entidades pueden haber sido modificadas o eliminadas desde que se cargaron las entidades. Actualizar entrada de ObjectStateManager


Aquí está la mejor solución para este problema: en la vista, agregue todas las ID (claves). Considere tener varias tablas con nombre (Primero, Segundo y Tercero)

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


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, TOut>(TIn input, TOut output, ICollection<string> 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 está desviando el estado del modelo del marco de la entidad. Piensa que "resultado" es el libro a seguir ahora y no quieres eso.

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


Debe eliminar db.Books.Attach(book);


Debe usar el método Entry () en caso de que desee actualizar todos los campos de su objeto. Además, tenga en cuenta que no puede cambiar la identificación del campo (clave), por lo tanto, primero configure la Id al mismo tiempo que 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(); }


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


Entonces, tiene una entidad que se actualiza y desea actualizarla en la base de datos con la menor cantidad de código ...

La concurrencia siempre es complicada, pero supongo que solo quieres que tus actualizaciones ganen. Así es como lo hice para mi mismo caso y modifiqué los nombres para imitar sus clases. En otras palabras, simplemente cambie attach para add , 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(); } }


Estás intentando actualizar el registro (lo 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(); } }


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. Utiliza primero el código de 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; }

Aquí está el código completo:

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


Esto si para Entity Framework 6.2.0.

Si tiene un DbSet específico y un elemento que necesita actualizarse o crearse:

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

Sin embargo, esto también se puede usar para un DbSet genérico con una sola clave primaria o una clave primaria compuesta.

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


He estado revisando el código fuente de Entity Framework y encontré una forma de actualizar una entidad si conoces la propiedad Key:

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

De lo contrario, verifique la implementación de AddOrUpdate para obtener ideas.

¡Espero que esto ayude!


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


Para .net core

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


Puede usar el método AddOrUpdate :

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


Sé que ya se ha respondido bien algunas veces, pero me gusta la siguiente forma de hacerlo. Espero que ayude a alguien.

//attach object (search for row) TableName tn = _context.TableNames.Attach(new TableName { PK_COLUMN = YOUR_VALUE}); // set new value tn.COLUMN_NAME_TO_UPDATE = NEW_COLUMN_VALUE; // set column as modified _context.Entry<TableName>(tn).Property(tnp => tnp.COLUMN_NAME_TO_UPDATE).IsModified = true; // save change _context.SaveChanges();


Attach una entidad establecerá su estado de seguimiento en Unchanged . Para actualizar una entidad existente, todo lo que necesita hacer es establecer el estado de seguimiento en Modified . De acuerdo con los documentos EF6 :

Si tiene una entidad que sabe que ya existe en la base de datos pero a la que se han realizado cambios, puede indicarle al contexto que adjunte la entidad y establezca su estado en Modificado. Por ejemplo:

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


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