2015-07-28 7 views
5

Ich baue ein generisches Repository und alle anderen Methoden funktionieren mit Ausnahme der Aktualisierung. Dies ist der Code:Fehler bei der Aktualisierung der Entität in einem generischen Repository

Ich verwende AutoMapper, um mein Geschäftsmodell zu meinem Entitätsmodell zuzuordnen. In meinem Controller habe ich folgendes:

Das Modell funktioniert perfekt und es kommt mit dem Active-Wert als False durch. Aber es gibt mir den folgenden Fehler:

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. 

Wie kann ich das beheben? Ich habe mehrere Methoden ausprobiert, um keinen Erfolg zu haben. Added Generika 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: Geschäftsmodell

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

Sind Sie das gleiche 'DbContext' mit Entität abzurufen und Einheit zu aktualisieren? –

+0

Ja, es ist das gleiche. –

+0

Obwohl ich kein Fan von generischen Repositories bin - ich kann diesen Beitrag empfehlen, wie man einen erstellt: http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5 -verwende-mvc-4/Implementieren-der-Repository-und-Einheit-von-Arbeit-Muster-in-einem-asp-net-mvc-Anwendung. –

Antwort

5

Wenn Sie die gleiche DbContext für verwenden abgerufen und Update-Operationen, dann verfolgt Ihr Kontext Ihre Entität (Entität mit diesem Primärschlüssel) bereits bei der Aktualisierung. Von 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.

glaube ich Ihnen die Attach Aufruf fehlen (die Sie auf Kommentar). Bitte versuchen Sie es

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

Hallo Nikolai, danke für die informative Antwort. Ich habe Ihre Update-Methode ausprobiert, aber ich habe die gleiche Ausnahme, genau an dieser Stelle: db.Set ().Attach (Gegenstand); –

+0

Ich poste mein komplettes generisches Repository nur für den Fall, dass etwas aus ist. –

+0

Ein Hack ist 'AsNoTracking()' zu verwenden, wenn Sie Ihre Entity abrufen. So etwas wie 'var entity = context.Set () .AsNoTracking() SingleOrDefault (x => x.Id == 1);.'. Das Problem gibt (über eine kleine Leistung schlagen wegen des Mangels an Caching) ist, dass Sie 'Id' auf alle Unternehmen haben müssen, indem sie eine gemeinsame Schnittstelle zum Beispiel implementieren. –

0

Ich habe genau das gleiche Problem, alle anderen Methoden (Hinzufügen, Löschen, Get) arbeiten gut eine Ausnahme des Updates. ich den Fehler, wenn die DbContext versucht, die Einheit zu befestigen:

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

Diese Repository-Methode "studentRepository.Update (Student);" wird von der Service-Schicht aufgerufen.

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

Aber es funktionierte gut, wenn ich Mapper nicht

verwenden
//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(); 
      } 
Verwandte Themen