2015-07-28 10 views
5

Sto costruendo un repository generico e tutti gli altri metodi funzionano con l'eccezione di quello di aggiornamento. Questo è il codice:Errore nell'aggiornamento dell'entità in un repository generico

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

    } 

Sto usando AutoMapper per mappare il mio modello di business al mio Entity Model. Nel mio controller ho il seguente:

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

Il modello funziona perfettamente e viene fornito attraverso con il valore attivo come False. Tuttavia mi dà il seguente errore:

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. 

Come posso risolvere questo? Ho provato diversi metodi senza successo. Aggiunto generico Codice Repo:

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: Aggiunto 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: Modello di Business

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

Si sta utilizzando lo stesso 'DbContext' per recuperare entità e per aggiornare entità? –

+0

Sì, è lo stesso. –

+0

Anche se non sono un fan dei repository generici, posso raccomandare questo post su come costruirne uno: http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5 -utilizzando-mvc-4/attuazione-the-repository-e-di unità di lavoro-patterns-in-un-asp-net-mVC applicazione. –

risposta

5

Se si utilizza lo stesso DbContext sia per recuperare e operazioni di aggiornamento, quindi il tuo contesto tiene già traccia della tua entità (entità con questa chiave primaria) quando esegui l'aggiornamento. Da 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.

Penso che vi manca il Attach chiamata (che si commentata). Si prega di provare

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

Ciao Nikolai, grazie per la risposta informativa. Ho provato il tuo metodo di aggiornamento ma ho ottenuto la stessa eccezione, in particolare a questo punto: db.Set ().Attaccare (voce); –

+0

Pubblicherò il mio repository generico completo nel caso in cui qualcosa non sia attivo. –

+0

Un hack è usare 'AsNoTracking()' quando recuperi la tua entità. Qualcosa come "var entity = context.Set () .AsNoTracking(). SingleOrDefault (x => x.Id == 1);'. Il problema in questo caso (oltre a un piccolo impatto sulle prestazioni dovuto alla mancanza di memorizzazione nella cache) è che dovrai avere l'ID di tutte le entità, per esempio implementando un'interfaccia comune. –

0

ho lo stesso identico problema, tutti gli altri metodi (aggiungere, eliminare Get) stanno lavorando bene un'eccezione dell'aggiornamento. ottengo l'errore quando il DbContext sta cercando di collegare l'entità:

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

Questo metodo repository "studentRepository.Update (studente);" viene chiamato dal livello di servizio.

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

ma ha funzionato bene se io non uso 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(); 
      } 
Problemi correlati