Entity Framework保存GeoLocationType时重复创建Classification条目求助
问题:Entity Framework保存关联实体时,总是在外键表创建新条目
我刚接触Entity Framework,遇到一个问题:在GeoLocationType表中添加了指向Classification表的外键Classification_ID,但每当保存GeoLocationType时,都会在Classification表中创建新条目,哪怕对应的Classifications_Id在Classification表中已经存在。
模型代码
public partial class GeoLocationType : BaseEntity { public YesNoEnum? IsActive { get; set; } public YesNoEnum? IsAutoStoreLocation { get; set; } public virtual Classification classification { get; set; } } public partial class Classification : BaseEntity { public string code { get; set; } }
业务代码
if (model.Classifications_Id > 0) { model.Classifications = _ClassificationRepository .Find(p => p.Id == model.Classifications_Id) .FirstOrDefault(); } var entity = Mapper.Map<GeoLocationType>(model); Validate(entity); _GeoLocationTypeRepository.Add(entity); _uow.SaveChanges();
解决方案
核心原因
你的代码中,从仓库查询出来的Classification实例要么没有被EF上下文追踪(比如仓库默认用了AsNoTracking),要么映射后的GeoLocationType关联的classification处于Detached状态。当调用Add(entity)时,EF会递归标记整个对象图中所有未被追踪的实体为Added,因此会在Classification表创建新条目。
具体解决办法
方法1:直接使用外键属性(推荐)
在GeoLocationType模型中显式添加外键属性,无需加载关联实体就能完成关联:
public partial class GeoLocationType : BaseEntity { public YesNoEnum? IsActive { get; set; } public YesNoEnum? IsAutoStoreLocation { get; set; } // 添加外键属性 public int? Classification_ID { get; set; } public virtual Classification classification { get; set; } }
业务代码中,直接将视图模型的Classifications_Id映射到外键属性即可:
var entity = Mapper.Map<GeoLocationType>(model); // 若映射配置未自动处理,手动设置外键 entity.Classification_ID = model.Classifications_Id; Validate(entity); _GeoLocationTypeRepository.Add(entity); _uow.SaveChanges();
这种方式最直接,EF会自动关联已存在的Classification记录,不会创建新条目。
方法2:手动标记关联实体为Unchanged
如果必须加载Classification实体,在保存前手动将其状态设置为Unchanged,告诉EF该实体已存在于数据库:
var entity = Mapper.Map<GeoLocationType>(model); if (entity.classification != null) { // 将关联实体标记为已存在状态 _uow.Context.Entry(entity.classification).State = EntityState.Unchanged; } Validate(entity); _GeoLocationTypeRepository.Add(entity); _uow.SaveChanges();
方法3:确保关联实体被上下文追踪
检查ClassificationRepository的Find方法是否使用了AsNoTracking(),如果是,去掉该配置;或者查询后手动将实体附加到上下文:
// 附加实体到上下文,让EF开始追踪它 _uow.Context.Attach(entity.classification);
内容的提问来源于stack exchange,提问作者Amit Pal
相关产品推荐
相关产品推荐

