Como atualizar o registro usando o Entity Framework 6?

Estou a tentar actualizar o registo usando EF6. Primeiro encontrar o registro, se existir, atualizá-lo. Aqui está o meu 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;
        }
    }
}

Sempre que tento actualizar o registo usando o código acima, estou a receber este erro: -

{Sistema.Dado.Entidade.Infraestrutura.DbUpdateConcurrencyException: Store actualizar, inserir ou apagar a declaração afectou um número inesperado de linhas (0). As entidades podem ter sido modificadas ou suprimidas uma vez que as entidades estavam carregados. Actualizar O Gestor De Objectos entrie

Author: user1327064, 2014-09-17

14 answers

Você está tentando atualizar o registro (o que para mim significa "mudar um valor em um registro existente e salvá-lo de volta"). Então você precisa recuperar o objeto, fazer uma mudança, e salvá-lo.

using (var db = new MyContextDB())
{
    var result = db.Books.SingleOrDefault(b => b.BookNumber == bookNumber);
    if (result != null)
    {
        result.SomeValue = "Some new value";
        db.SaveChanges();
    }
}
 230
Author: Craig W., 2014-09-17 18:51:58

Estive a rever o código-fonte da estrutura de Entidades e encontrei uma forma de actualizar realmente uma entidade se souber a propriedade-Chave noutro caso, terá de verificar a implementação de adicionar Data:

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);
}
Espero que isto ajude!
 95
Author: Miguel, 2018-07-02 14:14:31

Pode utilizar o método AddOrUpdate:

db.Books.AddOrUpdate(book); //requires using System.Data.Entity.Migrations;
db.SaveChanges();
 40
Author: nicedev80, 2016-12-13 19:20:16

Então você tem uma entidade que é atualizada, e você quer atualizá-la na base de dados com a menor quantidade de código... A concorrência é sempre complicada, mas presumo que só queira que as suas actualizações ganhem. Eis como o fiz para o mesmo caso e modifiquei os nomes para imitar as tuas aulas. IOW, basta mudar anexar para adicionar, e funciona para mim:

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();
        }
    }
 10
Author: Duray Akar, 2017-05-12 17:23:54

Este código é o resultado de um teste para atualizar apenas um conjunto de colunas sem fazer uma consulta para retornar o registro primeiro. Usa primeiro o 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<T>( 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;
        }

Aqui está o 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 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<T>( 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<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);
        }
    }
 7
Author: Juan, 2016-01-11 02:37:52

Aqui está a melhor solução para este problema: na vista adicione todos os ID (chaves). Considere ter várias tabelas nomeadas (primeira, segunda e terceira)

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

Em 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);
}
 4
Author: Kumar R, 2016-12-22 12:24:43

Devias usar o. Método Entry () no caso de querer actualizar todos os campos do seu objecto. Tenha também em mente que você não pode alterar o ID do campo (Chave), portanto, primeiro defina o Id para alguns como você editar.

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();
}
 4
Author: Jarek, 2017-11-17 12:04:05

Você deve remover db.Books.Attach(book);

 3
Author: Renat Seyfetdinov, 2016-10-02 20:06:13
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();
}
 2
Author: Nikhil Dinesh, 2018-04-06 03:41:39

Aqui está o meu método pós-RIA de actualização da entidade (para o período de tempo 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();
}

Note que FrameworkTypeUtility.SetProperties() é uma função utilitária minúscula que escrevi muito antes do AutoMapper em 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);
        }
    }
}
 1
Author: rasx, 2015-03-07 03:31:32
Como o Renat disse, remova: db.Books.Attach(book);

Também, mude sua consulta de resultado para usar "AsNoTracking", porque esta consulta está jogando fora do estado modelo do framework de entidade. Ele pensa que "resultado" é o livro a seguir agora e você não quer isso.

var result = db.Books.AsNoTracking().SingleOrDefault(b => b.BookNumber == bookNumber);
 1
Author: Nez, 2017-08-10 15:25:26
Experimenta....

UpdateModel (book);

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;
        }
    }
}
 1
Author: Karan, 2017-12-07 09:17:15
Encontrei uma maneira que funciona muito bem.
 var Update = context.UpdateTables.Find(id);
        Update.Title = title;

        // Mark as Changed
        context.Entry(Update).State = System.Data.Entity.EntityState.Modified;
        context.SaveChanges();
 0
Author: Farhan, 2018-07-31 15:44:00

Eu sei que já foi respondido bem algumas vezes, mas eu gosto de baixo modo de fazer isso. Espero que ajude alguém.

//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();
 0
Author: PawelCz, 2018-09-12 14:26:41