EF6 AutoMapper6父/子行为不同 [英] EF6 AutoMapper6 Parent/Child different behavior

查看:75
本文介绍了EF6 AutoMapper6父/子行为不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚将整个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 childs 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆