EF6 AutoMapper6 ผู้ปกครอง/รองพฤติกรรมที่แตกต่างกัน

ฉันเพิ่งอัปเดตแอป WCF ทั้งหมดจาก EF4 / AutoMapper 1.1 เป็น EF6 / AutoMapper 6.0.0.2 และลักษณะการทำงานไม่เหมือนเดิมทั้งหมด

สิ่งนี้ใช้ไม่ได้สำหรับฉัน: Entity Framework - เพิ่ม Child Entity

ก่อน :

child.Parent = parentObject

OR

parentObject.Children.Add(child)

ได้ผลเหมือนกันแบบเรียลไทม์ (ขณะทำการดีบั๊ก == ก่อน SaveChanges) ดังนั้นฉันจึงตัดสินใจใช้ child.Parent = parentObject เพื่อให้อ่านง่าย child.Parent = parentObject เพิ่มลูกใน parentObject โดยอัตโนมัติ เด็กยังถูกเพิ่มเข้าไปใน db ด้วย

ตอนนี้ : child.Parent = parentObject ไม่เพียงพออีกต่อไป (ไม่ได้เพิ่มลูกใน db) ฉันต้องเพิ่ม parentObject.Children.Add(child) บางครั้งฉันต้องการลิงก์ child.Parent = parentObject ดังนั้นฉันจึงต้องเขียนทั้งสองบรรทัด ใครช่วยอธิบายให้ฉันฟังได้ไหมว่าทำไมมันไม่ทำงานอีกต่อไป

นอกจากนี้ : ฉันสามารถเขียน before :

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 ค้นหา id(int) ของเพศในตาราง REF_GENDER การแมปนี้เพียงพอที่จะตั้งค่า 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 ใหม่ลงใน db


person Flou    schedule 10.10.2018    source แหล่งที่มา


คำตอบ (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 ของ EntityReference<Parent> รหัสของ EF4.1 ไม่ได้เปิดเผยต่อสาธารณะ ดังนั้นเราจึงเดาได้เพียงว่าเกิดอะไรขึ้นภายในเท่านั้น มีสิ่งหนึ่งที่ชัดเจน: มันเปลี่ยนสถานะ childs เป็น Added -- ถ้า child ยังไม่ได้แนบไปกับบริบท

โชคดีที่ EF ละทิ้งการล็อคอินของผู้จำหน่ายที่เข้มงวดนี้เมื่อเปิดตัว DbContext API (ใน EF 4.1 ไม่น้อยไปกว่านี้) ตอนนี้คุณสมบัติที่สร้างขึ้นนี้ไม่มีอะไรนอกจากคุณสมบัติอัตโนมัติ:

public Parent Parent { get; set; }

ทำให้ง่ายต่อการรวมโหมดการทำงานกับ EF ที่เน้นฐานข้อมูลเป็นอันดับแรกและเน้นโค้ดเป็นอันดับแรก ในความเป็นจริงทั้งคลาสเอนทิตีที่เน้นโค้ดเป็นอันดับแรกและเน้นฐานข้อมูลเป็นอันดับแรกในตอนนี้

ราคา (ถ้าคุณต้องการ) คือ EF ไม่สามารถติดตามทุกสิ่งที่เกิดขึ้นได้อย่างใกล้ชิดเท่าที่ควร ก่อนหน้านี้ คลาสเอนทิตีทั้งหมดสืบทอดมาจาก EntityObject และ EF สามารถติดตามการโต้ตอบทั้งหมดได้ คำแถลง...

child.Parent = parentObject;

จะดึง child ที่ยังไม่ทราบเข้ามาในบริบทผ่าน parentObject ที่แนบมาด้วย

ตอนนี้ เมื่อมีคนตั้งค่า child.Parent จะไม่มีใครนอกจาก child รู้ว่าเกิดอะไรขึ้น แม้แต่ Parent ด้วยซ้ำ ซึ่งหมายความว่า: ไม่มีทาง ใดๆ ก็ตาม ที่ EF จะรับรู้ถึงการเปลี่ยนแปลงนี้ เมื่อตัวติดตามการเปลี่ยนแปลงดำเนินการ DetectChanges (ซึ่งเกิดขึ้นบ่อยมาก)

นั่นเป็นเหตุผลว่าทำไมการใช้ DbContext คุณต้องเพิ่มรายการย่อยใหม่ในบริบทด้วยตนเอง ไม่ว่าจะโดยการตั้งค่าสถานะอย่างชัดเจน หรือเพิ่มลงใน context.Children หรือโดยการเพิ่มลงใน parent.Children ซึ่งเป็นการเปลี่ยนแปลงที่ตัวติดตามการเปลี่ยนแปลง สามารถ ตรวจพบได้ หากมีการแนบ parent ไว้ด้วย

person Gert Arnold    schedule 13.10.2018
comment
คุณพูดถูก @Gert Arnold การย้ายจาก ObjectContext ไปยัง DbContext เป็นความแตกต่างอย่างมากในพฤติกรรมของคลาสเอนทิตี ขอบคุณสำหรับคำตอบและการจัดรูปแบบของคุณ ในที่สุดฉันก็เพิ่ม child.Parent = parentObject AND parentObject.Children.Add(child) เพื่อให้โค้ดของฉันทำงานได้อีกครั้ง และฉันก็ตั้งค่าผู้อ้างอิงไว้ใน Mapper เหมือนที่ฉันเขียน - person Flou; 16.10.2018
comment
ฉันเพิ่งย้ายข้อมูลเสร็จสิ้นหลังจากผ่านไปหนึ่งสัปดาห์ ฉันกำลังทดสอบประสิทธิภาพที่เพิ่มขึ้น และในทุกกรณีจะแย่กว่า ef4 ซึ่งแตกต่างจาก docs.microsoft.com/fr-fr/ef/ef6/fundamentals/Performance/ กล่าวว่า... ฉันค่อนข้างผิดหวัง :( - person Flou; 17.10.2018
comment
ใช่แล้ว นั่นเป็นเรื่องที่ไม่คาดคิด คุณสามารถลองถามคำถามเกี่ยวกับกรณีเฉพาะได้ จากที่กล่าวมาข้างต้น อาจมีบางสิ่งที่คุณควรทำแตกต่างออกไปใน EF6 เมื่อเปรียบเทียบกับ EF4 เช่น การใช้ การเชื่อมโยงคีย์ต่างประเทศ แทนที่จะเป็นสมาคมอิสระ - person Gert Arnold; 17.10.2018
comment
1 - ฉันคิดว่าฉันใช้ FK แทนการเชื่อมโยงแบบอิสระอยู่แล้ว แต่ฉันไม่แน่ใจ ฉันหมายถึงฉันมี FK public int PrincipalEntity_Id หนึ่งรายการแล้ว { get; ชุด; } (ไม่มี [ForeignKey(PrincipalEntity_Id)]) และคุณสมบัติการนำทางหนึ่งรายการ สาธารณะ Principal PrincipalEntity { get; ชุด; } แต่ฉันไม่ได้ใช้ [ForeignKey(PrincipalEntity_Id)] เพราะเป็นโค้ดที่สร้างขึ้นโดยอัตโนมัติ และฉันคิดว่ามันดีพอที่ EF6 จะเข้าใจ - person Flou; 19.10.2018
comment
2 - ฉันกำลังตรวจสอบเพื่อปรับปรุงประสิทธิภาพการโหลด ฉันเพิ่งสังเกตเห็นด้วย SQL Profiler ว่าการที่การสืบค้นใช้การโหลดแบบขี้เกียจ : เพียงหนึ่งการเลือก / ตำแหน่งสำหรับวัตถุที่สูงที่สุด จากนั้นฉันสังเกตเห็นว่า AutoMapper ทำการเลือก/ตำแหน่งจำนวนมากในขณะที่ทำแผนที่เนื่องจากการโหลดแบบ Lazy Loading ดูเหมือนไม่ค่อยได้ผล ! ดังนั้นฉันจึงลองใช้วิธี .Include (หลาย) ในแบบสอบถามหลัก: เป็นแบบสอบถามแบบรวมหลายรายการที่ดูเหมือนว่าจะมีประสิทธิภาพมากกว่าสำหรับฉัน แต่จากนั้นการแมปยังคงทำการเลือก/ตำแหน่งเท่าเดิม ดังนั้นฉันสงสัยว่า AutoMapper ยังคงสมเหตุสมผลหรือไม่ - person Flou; 19.10.2018
comment
ฉันขอแนะนำให้คุณถามคำถามใหม่โดยมีรายละเอียดเพียงพอที่จะตอบ ฉันไม่สามารถตอบคำถามนี้จากข้อมูลในความคิดเห็นของคุณได้ และยังอยู่นอกเหนือขอบเขตของคำถามนี้ด้วย - person Gert Arnold; 19.10.2018
comment
3 - ฉันลืมไปว่า... การแสดงไม่ได้แย่ที่สุด ฉันแค่ลืมเกี่ยวกับการประหารชีวิตแบบเย็นและอบอุ่น ในตอนท้ายผลลัพธ์ก็ค่อนข้างเหมือนเดิม - person Flou; 19.10.2018