เอนทิตีกรอบการรีเฟรชบริบท?


101

ฉันจะรีเฟรชบริบทได้อย่างไร ฉันมีเอนทิตีตามมุมมองจากฐานข้อมูลของฉันและเมื่อฉันทำการอัปเดตบนตารางหนึ่งเอนทิตีที่มีคุณสมบัติการนำทางไปยังมุมมองเอนทิตีกำลังอัปเดต แต่มุมมองไม่รีเฟรชสอดคล้องกับการอัปเดตใหม่ ... เพียงแค่ต้องการรับอีกครั้งจาก ฐานข้อมูล ขอบคุณ!

คำตอบ:


92

วิธีที่ดีที่สุดในการรีเฟรชเอนทิตีในบริบทของคุณคือทิ้งบริบทของคุณและสร้างขึ้นใหม่

หากคุณต้องการรีเฟรชเอนทิตีบางส่วนจริงๆและคุณใช้แนวทาง Code First กับคลาส DbContext คุณสามารถใช้

    public static void ReloadEntity<TEntity>(
        this DbContext context, 
        TEntity entity)
        where TEntity : class
    {
        context.Entry(entity).Reload();
    }

หากต้องการโหลดคุณสมบัติการนำทางคอลเลคชันซ้ำคุณสามารถใช้

    public static void ReloadNavigationProperty<TEntity, TElement>(
        this DbContext context, 
        TEntity entity, 
        Expression<Func<TEntity, ICollection<TElement>>> navigationProperty)
        where TEntity : class
        where TElement : class
    {
        context.Entry(entity).Collection<TElement>(navigationProperty).Query();
    }

อ้างอิง: https://msdn.microsoft.com/en-us/library/system.data.entity.infrastructure.dbentityentry.reload(v=vs.113).aspx#M:System.Data.Entity.Infrastructure.DbEntityEntry . โหลดใหม่


3
ฉันไม่สามารถทำให้สิ่งนี้ทำงานเพื่อโหลดคุณสมบัติการนำทางลูกซ้ำได้
Paul

@David คุณสามารถใช้ได้context.ReloadNavigationProperty(parent, p => p.Children);ถ้าคุณมีclass Parent { ICollection<Child> Children; }
Jinjinov

ใน EF Core คุณสามารถใช้ Query () โหลด () ได้เช่นcontext.Entry(order).Collection(o => o.NavigationProperty).Query().Load();
Rubenisme

ฉันไม่เข้าใจว่าทำไมโซลูชันนี้จึงได้รับการโหวตอย่างสูง context.Entry (เอนทิตี) .Collection <TElement> (navigationProperty) .Query () ไม่โหลดคอลเลกชันลูกซ้ำ มันให้เฉพาะคุณ Iqueryable แทนแบบสอบถามที่ใช้ในการรับคอลเลกชัน แท้จริงมันไม่ได้ทำอะไรเลย
statler

72
yourContext.Entry(yourEntity).Reload();

3
ขอบคุณสำหรับวิธีง่ายๆ ฉันไม่เห็นความจำเป็นในการห่อหุ้มสิ่งนี้ในวิธีการขยายเช่น RX_DID_RX ทำ
โทมัส

นี่เป็นเครื่องช่วยชีวิตสำหรับฉัน ขอบคุณ!
Kevin

19
โปรดทราบว่าสิ่งนี้ไม่ได้โหลดคุณสมบัติการนำทางคอลเลกชันซ้ำ แต่เฉพาะรายการเอนทิตีเท่านั้น
James Wilkins

28

หากคุณต้องการโหลดเอนทิตีเฉพาะใหม่ด้วย DbContextApi RX_DID_RX ได้ให้คำตอบแล้ว

หากคุณต้องการรีโหลด / รีเฟรชเอนทิตีทั้งหมดที่คุณโหลด:

หากคุณกำลังใช้ Entity Framework 4.1+ (อาจเป็น EF5 หรือ EF 6) DbContext API:

public void RefreshAll()
{
     foreach (var entity in ctx.ChangeTracker.Entries())
     {
           entity.Reload();
     }
}

หากคุณกำลังใช้ entityFramework 4 (ObjectContext API):

public void RefreshAll()
{
     // Get all objects in statemanager with entityKey
     // (context.Refresh will throw an exception otherwise)
     var refreshableObjects = (from entry in context.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted
                                               | EntityState.Modified
                                               | EntityState.Unchanged)
                                      where entry.EntityKey != null
                                      select entry.Entity);

     context.Refresh(RefreshMode.StoreWins, refreshableObjects);
}

คำแนะนำที่ดีที่สุดคือพยายามใช้ "บริบทสั้น ๆ " แล้วคุณจะหลีกเลี่ยงปัญหาประเภทนี้ได้

ฉันเขียนบทความสองสามบทความเกี่ยวกับเรื่องนี้:

https://christianarg.wordpress.com/2013/06/13/entityframework-refreshall-loaded-entities-from-database/


ทำได้ดีนี่!! บันทึกวันของฉัน!
Radu D

16

ใช้วิธีการรีเฟรช :

context.Refresh(RefreshMode.StoreWins, yourEntity);

หรือในทางเลือกอื่นทิ้งบริบทปัจจุบันของคุณและสร้างใหม่


@JMK อะไรที่ใช้ไม่ได้ที่นี่? ดูเหมือนว่าจะทำงานได้ดีสำหรับฉัน (EF 6.1.1)
Sebastian Krysmanski

@SebastianKrysmanski ฉันแสดงความคิดเห็นเมื่อเกือบปีที่แล้วอาจจะได้รับการแก้ไขตั้งแต่?
JMK

5
ฉันคิดว่ามันใช้ได้กับ objectcontext เท่านั้น แต่ไม่ใช่ dbcontext จำเป็นต้องมีการสนทนาระหว่างกัน
Emil

3
@batmaci ซึ่งสามารถทำได้อย่างง่ายดายด้วย((IObjectContextAdapter)dbContext).ObjectContext
Daniel Z.

3
ซึ่งไม่ได้ระบุไว้เลยไม่สมบูรณ์เล็กน้อย
user441521

6

บริบทโหลดซ้ำ () ไม่ได้ผลสำหรับฉันใน MVC 4, EF 5 ดังนั้นฉันจึงทำเช่นนี้

context.Entry(entity).State = EntityState.Detached;
entity = context.Find(entity.ID);

และมันทำงานได้ดี


1

EF 6

ในสถานการณ์ของฉัน Entity Framework ไม่ได้รับข้อมูลที่อัปเดตใหม่ สาเหตุอาจเกิดจากการอัปเดตข้อมูลนอกขอบเขต การรีเฟรชข้อมูลหลังจากดึงข้อมูลสามารถแก้ไขปัญหาของฉันได้

private void RefreshData(DBEntity entity)
{
    if (entity == null) return;

    ((IObjectContextAdapter)DbContext).ObjectContext.RefreshAsync(RefreshMode.StoreWins, entity);
}

private void RefreshData(List<DBEntity> entities)
{
    if (entities == null || entities.Count == 0) return;

    ((IObjectContextAdapter)DbContext).ObjectContext.RefreshAsync(RefreshMode.StoreWins, entities);
}

1
ฉันอยู่กับ EF6 ทำไมถึงดีกว่า a _context.Entry(entity).Reload();?
Csaba Toth

เท่าที่จำ.Reload()ได้ไม่มีใน EF6 @CsabaToth
Mahbubur Rahman

0

ไม่แนะนำให้รีเฟรชบริบท db ด้วยการโหลดซ้ำเนื่องจากการสูญเสียประสิทธิภาพ ดีพอและแนวทางปฏิบัติที่ดีที่สุดในการเริ่มต้นอินสแตนซ์ใหม่ของ dbcontext ก่อนที่จะดำเนินการแต่ละครั้ง นอกจากนี้ยังให้บริบทใหม่ล่าสุดสำหรับการดำเนินการแต่ละครั้ง

using (YourContext ctx = new YourContext())
{
   //Your operations
}

6
Dude .. การทิ้งบริบทของคุณทุกครั้งจะทำให้สิ่งที่คุณไม่ต้องการรีเฟรชซึ่งจะนำไปสู่ปัญหาด้านประสิทธิภาพ
LuckyLikey

3
นี่เป็นความคิดที่แย่มากเนื่องจากมีผลต่อความสามารถในการเขียนแบบทดสอบหน่วย หากโค้ดของคุณดับลงและแจ้งบริบทใหม่จะทำงานอย่างไรระหว่างการทดสอบหน่วย
ผู้ชนะ

5
มันจะมีประโยชน์สำหรับฉันและคนอื่น ๆ ถ้าคุณแสดงตัวอย่างมากกว่าการวิจารณ์
aog

เหมาะสำหรับเว็บไซต์ขนาดเล็ก
alikuli

-1

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

NewJobOrder newJobOrder = new NewJobOrder();
    newJobOrder.ShowDialog();
    if (newJobOrder.DialogResult == DialogResult.Cancel)
    {
        this.jobOrderTableAdapter.Fill(this.multiTechDBDataSet.JobOrder);
        }

ไม่มีแม้แต่บริบทที่นี่ นี่เป็นเรื่องเกี่ยวกับการเติมข้อมูลชุดข้อมูลซึ่งเป็นเทคโนโลยีที่แตกต่างกันอย่างสิ้นเชิง ทำไมคุณไม่เพียงแค่ลบคำตอบหากคุณไม่ทราบวิธีแก้ไขปัญหาในคำถาม ฉันจำได้ว่าเรามีข้อโต้แย้งเดียวกันกับคำตอบของคุณในเวอร์ชันแรก
เกิร์ตอาร์โนลด์

-7

ฉันทำให้หัวของตัวเองได้รับบาดเจ็บโดยไม่มีอะไรเลย! คำตอบนั้นง่ายมาก - ฉันเพิ่งกลับไปที่พื้นฐาน ...

some_Entities   e2 = new some_Entities(); //your entity.

เพิ่มบรรทัดนี้ด้านล่างหลังจากที่คุณอัปเดต / ลบ - คุณกำลังโหลดเอนทิตีของคุณอีกครั้งโดยไม่ต้องใช้วิธีการระบบแฟนซี

e2 = new some_Entities(); //reset.

3
นั่นจะ "ได้ผล" - มันเป็นความคิดที่แย่มากและจะมีผลตามมาอีก
Adam Hey
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.