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

查看:26
本文介绍了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

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,而且从 ObjectContextDbContext.这是实体类行为的巨大差异.

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;
    }
}

所以设置这个属性就是设置 EntityReferenceValue 属性.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 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 无法 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屋!

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