EF6 AutoMapper6父/子行为不同

时间:2018-10-10 16:09:34

标签: entity-framework-6 automapper

我刚刚将整个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添加到数据库中

1 个答案:

答案 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,则更改跟踪器 可以检测到此更改。