我刚刚将整个WCF应用程序从 EF4 / AutoMapper 1.1 更新为 EF6 / AutoMapper 6.0.0.2 ,其行为并不完全相同。
这对我不起作用: Entity Framework - Add Child Entity
之前:
child.Parent = parentObject
OR
parentObject.Children.Add(child)
具有实时相同的结果(在SaveChanges之前调试==时),因此我决定使用child.Parent = parentObject
来提高可读性。 child.Parent = parentObject
自动在parentObject中添加了一个孩子。该孩子也被添加到数据库中。
现在:child.Parent = parentObject
不够用了(在数据库中未添加子项),我必须添加parentObject.Children.Add(child)。有时我需要链接child.Parent = parentObject,所以我必须写两行。有人可以向我解释为什么它不再起作用了吗?
也: 我可以写之前:
Mapper.CreateMap< Patient, PATIENTENTITY >()
.ForMember(dest => dest.Gender, opt => opt.ResolveUsing< PatientGenderResolver >())
.ForMember(dest => dest.REF_GENDER, opt => opt.Ignore())
其中dest.Gender
是PK(int),而PatientGenderResolver在表REF_GENDER中找到性别的id(int)。借助ID解析程序,该映射足以实时设置PATIENTENTITY.REF_GENDER。
现在,设置了ID,但PATIENTENTITY.REF_GENDER保持为空。 我也尝试直接使用解析器设置PATIENTENTITY.REF_GENDER,但是它在表REF_GENDER中添加了性别...
那么,有人可以向我解释为什么它不再起作用了吗?
编辑 一些精度: 之前:
patientEntity = Mapper.PatientToEntity(patientModel);
//patientEntity.REF_GENDER is null
Context.PATIENTENTITIES.AddObject(patientEntity);
//patientEntity.REF_GENDER is set !
Context.SaveChanges();
现在:
patientEntity = Mapper.PatientToEntity(patientModel);
//patientEntity.REF_GENDER is null
Context.PATIENTS.Add(patientEntity);
//patientEntity.REF_GENDER is still null !
//patientEntity.REF_GENDER = Context.REF_GENDER.Find(patientEntity.Gender);//I am obliged to add this line everywhere for every REF !
Context.SaveChanges();
我的猜测是我遇到的两个问题是相关的
编辑 我只是回到我的项目中。我现在有EF6和Automapper 1.1。 问题完全相同,所以我猜想Automapper没有涉及。
编辑 我解决了REF_GENDER问题
patientEntity = Mapper.PatientToEntity(patientModel, Context);
public PATIENT PatientToEntity(Patient patient, EntityContainer context)
{
PATIENT entity = AutoMapper.Mapper.Map<Patient, PATIENT>(patient);
if (patient.Id == null || patient.Id == Guid.Empty)
entity.PatientId = Guid.NewGuid();
else
entity.PatientId = patient.Id;
entity.REF_GENDER = context.REF_GENDER.Find(entity.Gender);
return entity;
}
显然,上下文必须相同,否则将新的REF_GENDER添加到数据库中
答案 0 :(得分:1)
您没有明确提及它,但您不仅从EF 4移到了6,还从ObjectContext
移到了DbContext
。那是实体类在行为上的巨大差异。
在ObjectContext
API中,生成的实体类中填充了与它们所涉及的上下文紧密协作的代码。像child.Parent
这样的引用属性如下:
public Parent Parent
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Parent>("model.FK_Child_Parent", "Parent").Value;
}
set
{
((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Parent>("model.FK_Child_Parent", "Parent").Value = value;
}
}
因此,设置此属性将设置Value
的{{1}}属性。 EF4.1的代码不是公开的,因此我们只能猜测里面发生了什么。有一件事很清楚:如果EntityReference<Parent>
尚未附加到上下文,它将child
的状态更改为Added
。
幸运的是,EF在发布child
API时放弃了这种严格的供应商锁定(在EF 4.1中同样如此)。现在,此生成的属性不过是自动属性:
DbContext
这使得统一使用EF的数据库优先和代码优先模式变得容易得多。实际上,现在代码优先和数据库优先的实体类都是POCO。
价格(如果您愿意的话)是EF无法像以前那样密切跟踪发生的一切。 之前,所有实体类都继承自public Parent Parent { get; set; }
,EF可以跟踪其所有交互。声明...
EntityObject
将通过所附的child.Parent = parentObject;
将未知的child
绘制到上下文中。
现在,当有人设置parentObject
时,只有child.Parent
知道发生了什么,甚至child
都不知道。这意味着:当EF的变更跟踪器执行Parent
时(因为它非常频繁地执行),EF没有任何任何事情可以知道这一变更。
这就是为什么使用DetectChanges
时必须自己显式设置其状态,或将其添加到DbContext
来将新子项添加到上下文中的原因。或通过将其添加到context.Children
中,如果附加了parent.Children
,则更改跟踪器 可以检测到此更改。