我有一个三层应用程序。图层是DAL,BL和UI。我正在使用automapper将从数据库上下文中获取的实体转换为上层。据我所知,EF不再能够跟踪映射的实体。
无论如何,我面临的问题发生在更新DB中存在的实体时,更确切地说是DTO实体更新EF实体。来自上层的DTO被映射回实体以完成更新操作。但是,从DTO实体映射并且其所有导航属性和集合在上下文中不存在,因为它们未被跟踪。
EF接受此实体及其实体图作为新信息,而不考虑该实体及其中包含的某些实体已经存在于上下文中的事实。
这里有一些例子。
我有两个模型,Student
和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; }
}
我的背景:
public class SchoolContext : DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set;}
}
我的StudentMap
和StandardMap
看起来与上面提到的模型相同。
自动播放器配置文件:
public class AutomapperProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Student, StudentMap>();
Mapper.CreateMap<StudentMap, Student>();
Mapper.CreateMap<Standard, StandardMap>();
Mapper.CreateMap<StandardMap, Standard>();
}
}
这里是我运行的代码:
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();
}
我会感谢任何帮助!我已经检查了我能做什么但是徒劳无功。
答案 0 :(得分:3)
行Standard
提供了例外情况,因为您已添加StandardID
个实体schoolContext.Standards.Add(standard);
之前Standard
。
解决方案:
StandardMap.StandardID
StandardMap
个实体
将Standard
转移对象的属性值映射到请求的Mapper.Map<Source, Destination>(source, destination);
实体(手动或使用Mapper.CreateMap<StudendMap, Student>.
ForMember(
x => x.Standard,
m => m.ResolveUsing(
s => Context.Set<Standard>.Find(s.StandardID)))
)
保存更改
ADDED
如果您想使用AutoMapper,您必须正确配置mapper以从上下文请求嵌套实体,而不是创建它们,例如:
library(ggplot2)
library(XML)
tab <- readHTMLTable("http://www.50states.com/abbreviations.htm", which=1)
df$region <- tolower(tab[match(df$State, tab[, 2]), 1])
states <- map_data("state")
choro <- merge(states, df, sort = FALSE, by = "region")
choro <- choro[order(choro$order), ]
ggplot(choro, aes(long, lat.x)) +
geom_polygon(aes(group = group, fill = Count), colour="grey55") +
coord_quickmap() +
facet_wrap(~Year)
答案 1 :(得分:0)
附加完整图表是一项复杂的任务。在这种情况下,EF将Student实例附加为已添加,这是将对象附加到集合时的行为。
为避免招收新生,您应首先将所有标准学生附加到上下文中,以便开始跟踪(未经修改),然后附加standardEf实体。