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
或
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
已经不够用了(db 中没有添加子项),我必须添加 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 中找到 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 中添加了一个 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
的 Value
属性.EF4.1 的代码是不公开的,所以我们只能猜测里面发生了什么.有一点很清楚:它将 child
的状态更改为 Added
—— 如果 child
尚未附加到上下文.
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 无法 whatsoever 意识到此更改.
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屋!