ไม่สามารถลบวัตถุได้เนื่องจากไม่พบใน ObjectStateManager


114

ฉันได้รับข้อผิดพลาดนี้ "ไม่สามารถลบวัตถุได้เนื่องจากไม่พบใน ObjectStateManager"

รหัสของฉันคือ:

    protected MyEntities sqlEntities;

    public virtual void Delete(TEntity entity)
    {
        System.Type t = typeof(TEntity);
        sqlEntities.DeleteObject(entity);
        sqlEntities.SaveChanges();
    }

5
ขออภัยมีปัญหาในโค้ดที่ใช้อ็อบเจ็กต์ datacontext อื่นเพื่อดึงข้อมูลและลบบันทึก
Sami

ฉันมีข้อผิดพลาดเช่นนี้: var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity);ฉันพยายามสร้างเอนทิตีจำลองด้วยการตั้งค่า PK อย่างถูกต้องโดยหวังว่า Entity Framework จะเรียก DeleteObject ตาม PK
C.Tewalt

คำตอบ:


156

หมายความว่าไม่ได้แนบเอนทิตี (ไม่ได้โหลดโดยอินสแตนซ์บริบทเดียวกัน) ลองสิ่งนี้:

protected MyEntities sqlEntities;

public virtual void Delete(TEntity entity)
{
    sqlEntities.Attach(entity);
    sqlEntities.DeleteObject(entity);
    sqlEntities.SaveChanges();
}

1
ขอบคุณ Ladislav สิ่งนี้ช่วยฉันได้เมื่อฉันมีสองบริบทที่เกิดขึ้นเมื่อลบข้อมูลลูกจากผู้ปกครองซึ่งถูกเรียกจากบริบทที่แตกต่างกันนอก TransactionScope ย้ายการเรียกผู้ปกครองภายในขอบเขตและบริบทเดียวกันและปัญหาของฉันได้รับการแก้ไข
dan richardson

1
@Ladislav: ถ้าฉันใช้. Attach ฉันได้รับข้อผิดพลาดที่แตกต่างกัน: "ไม่สามารถอ้างอิงวัตถุเอนทิตีโดยอินสแตนซ์ของ IEntityChangeTracker หลายอินสแตนซ์ได้" หมายความว่ามีอินสแตนซ์ออบเจ็กต์อื่นที่ป้องกันการลบอยู่แล้วหรือไม่?
Matt

2
@ แมท: ไม่ได้หมายความว่าวัตถุของคุณถูกแนบไปกับบริบทอื่นแล้ว ไม่สามารถติดสองตัวพร้อมกันได้ คุณควรใช้บริบทเดิมเพื่อลบเอนทิตี
Ladislav Mrnka

@Ladislav: ขอบคุณที่ช่วยฉันในการค้นหาเพิ่มเติม - ฉันพบคำถามนี้ซึ่งดูเหมือนจะตอบได้ว่าจะแก้ไขอย่างไร: เป็นไปได้ที่จะตรวจสอบว่าวัตถุถูกแนบกับบริบทข้อมูลใน Entity Framework แล้วหรือไม่? . คุณพูดถูกนี่น่าจะเป็นปัญหาในกรณีของฉัน ขอบคุณสำหรับคำตอบด่วน!
แมตต์

ขอบคุณสำหรับการช่วยเตือนฉันได้แนบไว้ตอนที่เพิ่งอัปเดตบันทึก แต่ไม่ใช่ตอนที่ฉันกำลังลบบันทึก
pinmonkeyiii

60

คำชี้แจงเล็กน้อยเกี่ยวกับคำตอบโดย Ladislav Mrnka (ซึ่งควรเป็นคำตอบที่ยอมรับได้)

ถ้าชอบฉันคุณมีโค้ดในรูปแบบดังนี้:

using (var context = new MyDataContext())
{
    context.MyTableEntity.Remove(EntytyToRemove);
    var nrOfObjectsChanged = context.SaveChanges();
}

.. แล้วนี่คือสิ่งที่คุณต้องการทำ:

using (var context = new MyDataContext())
{
    // Note: Attatch to the entity:
    context.MyTableEntity.Attach(EntityToRemove);

    context.MyTableEntity.Remove(EntityToRemove);
    var nrOfObjectsChanged = context.SaveChanges();
}

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


1
ฉันใช้วิธีนี้และได้รับข้อยกเว้น: "จัดเก็บการอัปเดตแทรกหรือลบคำสั่งส่งผลกระทบต่อจำนวนแถวที่ไม่คาดคิด (0) เอนทิตีอาจถูกแก้ไขหรือลบเนื่องจากเอนทิตีถูกโหลดรีเฟรชรายการ ObjectStateManager"
kat1330

11

เพียงเพื่อให้เหมาะสมกับคำอธิบายของ Kjartans:

ฉันมี:

public Project DeleteProject(int id)
    {
        using (var context = new Context())
        {
            var p = GetProject(id);
            context.Projects.Remove(p);
            context.SaveChanges();
            return p;
        }
    }

ปัญหาคือฉันใช้วิธีของฉันเอง (GetProject ()) เพื่อรับเอนทิตี (ด้วยเหตุนี้จึงใช้บริบทอื่นเพื่อโหลดเอนทิตี):

public Project GetProject(int id)
    {
        using (var context = new Context())
        {
            var project = context.Projects
                .Include(p => p.Reports.Select(q => q.Issues.Select(r => r.Profession)))
                .Include(p => p.Reports.Select(q => q.Issues.Select(r => r.Room)))
                .SingleOrDefault(x => x.Id == id);
            return project;      
        }
    }

วิธีแก้ปัญหาหนึ่งคือการแนบเอนทิตีที่โหลดเป็นสถานะ Kjartan อีกวิธีหนึ่งอาจเป็นโซลูชันของฉันเพื่อโหลดเอนทิตีภายในบริบทเดียวกัน:

public Project DeleteProject(int id)
    {
        using (var context = new Context())
        {
            var p = context.Projects.SingleOrDefault(x => x.Id == id);
            if (p == null)
                return p;

            context.Projects.Remove(p);
            context.SaveChanges();
            return p;
        }
    }

2

ฉันรู้ว่าคำถามนี้ค่อนข้างเก่า แต่ข้อใดข้างต้นไม่ได้ผลสำหรับฉันเนื่องจากฉันกำลังลบการลงทะเบียนจากคลาส / บริการมากกว่าหนึ่งคลาสและแต่ละรายการกำลังสร้างอินสแตนซ์บริบทการเชื่อมต่อฐานข้อมูลของตัวเอง

สิ่งที่ฉันทำเพื่อแก้ปัญหาคือการส่งบริบทที่สร้างขึ้นครั้งแรกไปยังชั้นเรียน / บริการที่เหลือซึ่งจะเข้าถึงฐานข้อมูล

ตัวอย่างเช่นฉันserviceAกำลังจะลบการลงทะเบียนบางรายการและโทรserviceBและserviceCทำเช่นเดียวกันกับการลงทะเบียนของพวกเขา

ฉันก็จะลบลงทะเบียนของฉันในserviceAและผ่านเป็นพารามิเตอร์บริบทที่สร้างขึ้นบนserviceAไปและserviceBserviceC



1

ในกรณีที่วิธีข้างต้นไม่ได้ผลคุณสามารถลองวิธีนี้:

context.Entry(yourObject).State = System.Data.Entity.EntityState.Deleted; context.SaveChanges();


0

คุณควรแน่ใจว่ามีวัตถุของคุณอยู่ในรายการที่คุณพยายามจะลบออกคุณควรวางเงื่อนไขต่อไปนี้

ถ้า (context.entity.contains (วัตถุของคุณ))

ย้ายมัน.

หากคุณมีเงื่อนไขที่ซับซ้อนสำหรับความเท่าเทียมกันคุณควรแทนที่วิธีการที่เท่าเทียมกันในคลาสเอนทิตีเพื่อวางเงื่อนไขของคุณสำหรับความเท่าเทียมกันเพื่อให้ได้วิธีที่เหมาะสมสำหรับเมธอดส่วนขยาย"entity.contains"


0

ตรวจสอบให้แน่ใจว่าโมเดลที่ส่งผ่านไปยัง Remove (Entity) ตรงกับระเบียนฐานข้อมูล

บางครั้งอาจเป็นไปได้ที่จะส่งแบบจำลองโดยไม่มีฟิลด์บางฟิลด์เช่น Id หรือ Date เก็บไว้ใน @ html.Hiddenfor หากคุณโพสต์เป็นแบบฟอร์ม

วิธีที่ดีที่สุดคือการส่ง ID และรับเอนทิตีโดยใช้เมธอด Find (Id) และส่งต่อไปยัง Remove (Entity)

หวังว่านี่จะช่วยใครบางคนได้


0

ฉันได้รับปัญหานี้และแก้ไขได้ เพียงคัดลอกโค้ดด้านล่าง:

sqlEntities.Attach(entity);
sqlEntities.Remove(entity);
sqlEntities.SaveChanges();

0

ในกรณีของฉันมีบริบทหนึ่ง แต่ฉันได้รับเอนทิตีที่มีตัวเลือก 'AsNoTracking'

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