简体   繁体   中英

Error Updating Entity in a Generic Repository

I am building a Generic Repository and all other methods work with the exception of the update one. This is the code:

 public void Update(T1 obj)
    {
        T2 item = Mapper.Map<T1, T2>(obj);
        //db.Entry(item).State = EntityState.Modified;
        //db.Set<T2>().Attach(item);
        db.Entry<T2>(item).State = EntityState.Modified;
        db.SaveChanges();

    }

I am using AutoMapper to map my business model to my Entity Model. In my controller I have the following:

        userModel = userIDService.SelectByID(id);
        userModel.Active = false;
        userIDService.Update(userModel);

The model works perfectly and it comes through with the Active value as False. Yet it gives me the following error:

Attaching an entity of type 'Data.UserIdentification' failed because 
another entity of the same type already has the same primary key value. 
 This can happen when using the 'Attach' method or setting the state of 
 an entity to 'Unchanged' or 'Modified' if any entities in the graph 
have conflicting key values. This may be because some entities are new 
and have not yet received database-generated key values. In this case 
 use the 'Add' method or the 'Added' entity state to track the graph and 
 then set the state of non-new entities to 'Unchanged' or 'Modified' as 
appropriate.

How can I fix this? I've tried several methods to no success. Added Generic Repo Code:

public class GenericRepository<T1, T2>:IGenericRepository<T1> 
    where T1 : class
    where T2: class

{
    private Data.Entities db = null;
    private DbSet<T2> table = null;

    public GenericRepository()
    {
        this.db = new Data.Entities();
        table = db.Set<T2>();
    }

    public GenericRepository(Entities db)
    {
        this.db = db;
        table = db.Set<T2>();
    }

    public IQueryable<T1> SelectAll()
    {
        return table.ToList().AsQueryable().Select(x => Mapper.Map<T2, T1>(x));
    }

    public T1 SelectByID(object id)
    {
        return Mapper.Map<T2, T1>(table.Find(id));
    }

    public void Insert(T1 obj)
    {
        T2 item = Mapper.Map<T1, T2>(obj);
        table.Add(item);
    }

    public void Update(T1 obj)
    {
        //T2 item = Mapper.Map<T1, T2>(obj);
        //table.Attach(item);
        //db.Entry<T2>(item).State = EntityState.Modified;
        //db.SaveChanges();
        T2 item = Mapper.Map<T1, T2>(obj);
        db.Set<T2>().Attach(item);
        db.Entry<T2>(item).State = EntityState.Modified;
        db.SaveChanges();




    }

    public void Delete(object id)
    {
        T2 existing = table.Find(id);
        table.Remove(existing);
    }

    public void Save()
    {
        db.SaveChanges();
    }

EDIT2: Added UserIdentification Entity

 public partial class UserIdentification
{
    public System.Guid id { get; set; }
    public System.Guid user_id { get; set; }
    public int id_type { get; set; }
    public System.DateTime expiration_date { get; set; }
    public System.DateTime Created { get; set; }
    public Nullable<bool> Active { get; set; }

    public virtual IdentificationType IdentificationType { get; set; }
    public virtual UserInfo UserInfo { get; set; }
}

EDIT 3: Business Model

    public Guid id { get; set; }
    public System.Guid user_id { get; set; }
    public int id_type { get; set; }
    public System.DateTime expiration_date { get; set; }
    public System.DateTime Created { get; set; }
    public Nullable<bool> Active { get; set; }
    public virtual IdentificationType IdentificationType { get; set; }

If you use the same DbContext for both retrieve and update operations, then your context already tracks your entity (entity with this primary key) when you update. From MSDN :

Changing the state of a tracked entity

You can change the state of an entity that is already being tracked by setting the State property on its entry. For example:

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

using (var context = new BloggingContext()) 
{ 
    context.Blogs.Attach(existingBlog); 
    context.Entry(existingBlog).State = EntityState.Unchanged; 

    // Do some more work...  

    context.SaveChanges(); 
}

Note that calling Add or Attach for an entity that is already tracked can also be used to change the entity state. For example, calling Attach for an entity that is currently in the Added state will change its state to Unchanged.

I think you are missing the Attach call (that you commented out). Please try

public void Update(T1 obj)
{
    T2 item = Mapper.Map<T1, T2>(obj);
    db.Set<T2>().Attach(item);
    db.Entry<T2>(item).State = EntityState.Modified;
    db.SaveChanges();
}

I'm just going to leave this here:

https://vimeo.com/131633177

I have the exact same problem, all other methods (Add, Delete, Get) are working fine a exception of the update. I get the error when the dbContext is trying to attach the entity:

    public virtual void Update(T entity)
    {
        dbSet.Attach(entity);
        dataContext.Entry(entity).State = EntityState.Modified;
    }

This repository method "studentRepository.Update(student);" is called from the service layer.

    public StudentAdapterModel SaveStudent(StudentAdapterModel studentAdapterModel)
    {
        try
        {
            Student student = null;
            if (studentAdapterModel.EventId == 0)
            {
                student = new Student();
                student = Mapper.Map<StudentAdapterModel, Student>(studentAdapterModel);
                studentRepository.Add(student);
            }
            else
            {
                //student = studentRepository.GetById(studentAdapterModel.EventId);
                student = studentRepository.Get(e => e.EventId == studentAdapterModel.EventId);
                try
                {
                    student = Mapper.Map<StudentAdapterModel, Student>(studentAdapterModel);

                }
                catch (Exception ex2)
                {
                    string errMess = ex2.ToString().Trim();
                }

                auctionEventRepository.Update(auctionEvent);

            }
            unitOfWork.Commit();
            studentAdapterModel.EventId = student.EventId;
            return studentAdapterModel;
        }
        catch (Exception ex)
        {
            string errMess = ex.ToString().Trim();
        }
        return null;
    }

But it worked fine if I don't use Mapper

    //student = studentRepository.GetById(studentAdapterModel.EventId);
            student = studentRepository.Get(e => e.EventId == studentAdapterModel.EventId);
            try
            {
                //student = Mapper.Map<StudentAdapterModel, Student>(studentAdapterModel);
                student.Name = StudentAdapterModel.Name;
            }
            catch (Exception ex2)
            {
                string errMess = ex2.ToString().Trim();
            }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM