EF6 AutoMapper6父/子行为不同 [英] EF6 AutoMapper6 Parent/Child different behavior
问题描述
我刚刚将整个WCF应用程序从 EF4/AutoMapper 1.1 更新为 EF6/AutoMapper 6.0.0.2 ,其行为并不完全相同.
I just updated an entire WCF app from EF4 / AutoMapper 1.1 to EF6 / AutoMapper 6.0.0.2 and the behavior is not completely the same.
这对我不起作用: 实体框架-添加子实体
之前:
child.Parent = parentObject
OR
parentObject.Children.Add(child)
具有实时相同的结果(在SaveChanges之前调试==时),因此我决定使用child.Parent = parentObject
来提高可读性. child.Parent = parentObject
自动在parentObject中添加了一个子代.该孩子也被添加到数据库中.
had the same result in real time (while debugging == before SaveChanges), so I decided to use child.Parent = parentObject
for the readability. child.Parent = parentObject
added a child in parentObject automatically. The child was also added to the db.
现在:child.Parent = parentObject
不再足够(在数据库中未添加子项),我必须添加parentObject.Children.Add(child).有时我需要链接child.Parent = parentObject,所以我必须写两行.有人可以向我解释为什么它不再起作用了吗?
Now : child.Parent = parentObject
is not enough anymore (child is not added in the db), I have to add parentObject.Children.Add(child). Sometimes I need the link child.Parent = parentObject, so I have to write both lines. Can someone explain to me why it does not work anymore ?
也: 我可以写之前:
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.
where dest.Gender
is the PK(int) and PatientGenderResolver find the id(int) of the Gender in the table REF_GENDER. This mapping was enough to set PATIENTENTITY.REF_GENDER in real time thanks to the Id resolver.
现在,设置了ID,但PATIENTENTITY.REF_GENDER保持为空. 我也尝试直接使用解析器设置PATIENTENTITY.REF_GENDER,但是它在表REF_GENDER中添加了性别...
Now the id is set but PATIENTENTITY.REF_GENDER remains null. Also I tried to set directly PATIENTENTITY.REF_GENDER with a resolver but it add a Gender in the table REF_GENDER...
再说一次,有人可以向我解释为什么它不再起作用了吗?
So again, can someone explain to me why it does not work anymore ?
编辑 一些精度: 之前:
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();
我的猜测是我遇到的两个问题是相关的
My guess is that the two problems I have are related
编辑 我只是回到我的项目中.我现在有EF6和Automapper 1.1. 问题完全一样,所以我猜想Automapper没有涉及.
EDIT I just go back in my project. I now have EF6 and Automapper 1.1. The problems are exactly the sames so I guess Automapper is not involved.
编辑 我解决了REF_GENDER问题
EDIT I get around the REF_GENDER issue with
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添加到数据库中
Apparently, the context has to be the same otherwise a new REF_GENDER is added to the db
推荐答案
您没有明确提及它,但您不仅从EF 4转到了6,还从ObjectContext
转到了DbContext
.那是实体类在行为上的巨大差异.
You don't mention it explicitly, but you didn't only move from EF 4 to 6, but also from ObjectContext
to DbContext
. That's a tremendous difference in behavior of the entity classes.
在ObjectContext
API中,生成的实体类中填充了与它们所涉及的上下文紧密协作的代码.像child.Parent
这样的引用属性如下所示:
In the ObjectContext
API the generated entity classes were stuffed with code that cooperated closely with the context they were involved in. A reference property like child.Parent
would look like:
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;
}
}
因此,设置此属性将设置EntityReference<Parent>
的Value
属性. EF4.1的代码不是公开的,因此我们只能猜测里面发生了什么.有一件事很清楚:如果child
尚未附加到上下文,它将child
的状态更改为Added
.
So setting this property is setting the Value
property of an EntityReference<Parent>
. EF4.1's code isn't public, so we can only guess what happens inside. One thing is clear: it changes child
s state into Added
-- if child
wasn't yet attached to the context.
幸运的是,EF在发布DbContext
API时放弃了这种严格的供应商锁定(在EF 4.1中同样如此).现在,此生成的属性不过是自动属性:
Fortunately EF abandoned this rigid vendor lock-in when it released the DbContext
API (in EF 4.1 no less). Now this generated property isn't anything but an auto-property:
public Parent Parent { get; set; }
这使统一使用EF的数据库优先和代码优先模式变得更加容易.实际上,现在代码优先和数据库优先的实体类都是POCO.
This made it much easier to unify the database-first and code-first modes of working with EF. In fact, both code-first and database-first entity classes were POCOs now.
价格(如果愿意的话)是EF无法像以前那样密切跟踪发生的一切. 之前,所有实体类均继承自EntityObject
,EF可以跟踪其所有交互.声明...
The price (if you like) is that EF can't keep as close a track of everything that happens as it could before. Before, all entity classes inherited from EntityObject
, and EF could keep track of all of their interactions. The statement...
child.Parent = parentObject;
会通过所附的parentObject
将未知的child
绘制到上下文中.
would draw the yet unknown child
into the context through the attached parentObject
.
现在,当有人设置了child.Parent
时,只有child
没人知道发生了什么,甚至Parent
也不知道.这意味着:当EF的变更跟踪器执行DetectChanges
时(因为它非常频繁地执行),EF不会任何事情知道此变更.
Now, when someone sets child.Parent
, no one but child
knows what happened, not even Parent
. Which means: there is no way whatsoever for EF to become aware of this change when its change tracker executes DetectChanges
(as it does very frequently).
这就是为什么使用DbContext
时必须自己显式设置其状态,或将其添加到context.Children
来将新的子代添加到上下文中.或通过将其添加到parent.Children
中(如果附加了parent
,则更改跟踪器 可以检测到此更改).
That's why using DbContext
you have to add a new child to the context yourself, either by explicitly setting its state, or adding it to context.Children
. Or by adding it to parent.Children
, which is a change the change tracker can detect, if parent
is attached.
这篇关于EF6 AutoMapper6父/子行为不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!