I have a three layer application. The layers are DAL, BL and UI. I'm using automapper to transform my entities taken from database context to up level layers. As far as I can see, the mapped entities are failed to be tracked by EF any longer.
Anyway the problem which I face occurs at the moment of updating the entities existing in DB, to be more exact the updating EF entities by DTO entities. The DTO from upper layer is mapped back to entity to complete update operation. However mapped from DTO entity and all its navigation properties and collections don't exist in context because they are not being tracked.
EF accepts this entity and its entities graph as a new information without taking into consideration the fact that this entity and some entities that included in it can already exist in context.
Here some example.
I have two models, Student and Standard.
public class Student
{
[Key]
public Guid StudentID { get; set; }
public string StudentName { get; set; }
public DateTime DateOfBirth { get; set; }
public decimal Height { get; set; }
public float Weight { get; set; }
public Standard Standard { get; set; }
}
public class Standard
{
[Key]
public Guid StandardId { get; set; }
public string StandardName { get; set; }
public ICollection<Student> Students { get; set; }
}
My context:
public class SchoolContext : DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set;}
}
I also have a StudentMap and StandardMap that look the same as the models mentioned above.
Automapper profile:
public class AutomapperProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Student, StudentMap>();
Mapper.CreateMap<StudentMap, Student>();
Mapper.CreateMap<Standard, StandardMap>();
Mapper.CreateMap<StandardMap, Standard>();
}
}
And here the code I run:
Mapper.AddProfile(new AutomapperProfile());
var student1 = new Student
{
DateOfBirth = DateTime.Now,
Height = 195,
StudentID = Guid.NewGuid(),
StudentName = "Bob",
Weight = 144
};
var student2 = new Student
{
DateOfBirth = DateTime.UtcNow,
Height = 170,
StudentID = Guid.NewGuid(),
StudentName = "John",
Weight = 95,
};
var standard = new Standard
{
StandardId = Guid.NewGuid(),
StandardName = "New Standard",
Students = new List<Student> { student1 }
};
using (var schoolContext = new SchoolContext())
{
schoolContext.Standards.Add(standard);
schoolContext.Students.Add(student2);
schoolContext.SaveChanges();
var standardInContext = schoolContext.Standards.First();
var studentInContext = schoolContext.Students.First(student => student.StudentID == student2.StudentID);
var mappedStandad = Mapper.Map<Standard, StandardMap>(standardInContext);
var mappedStudent = Mapper.Map<Student, StudentMap>(studentInContext);
mappedStandad.Students.Add(mappedStudent);
var standardEf = Mapper.Map<StandardMap, Standard>(mappedStandad);
//On attach attempt exception will be thrown
//because standard with the same Id already exist in context
schoolContext.Set<Standard>().Attach(standardEf);
schoolContext.Entry(standardEf).State = EntityState.Modified;
// with this solution two additional student will be added to the context,
// exception will be thrown on SaveChanges, because students with
// same ID already exist
// var standardEf = Mapper.Map(mappedStandad, standardInContext);
// schoolContext.Set<Standard>().Attach(standardEf);
// schoolContext.Entry(standardEf).State = EntityState.Modified;
schoolContext.SaveChanges();
}
I'll be thankful for any help! I've examined whatever I could but in vain.