Nesne, ObjectStateManager'da bulunamadığından silinemez


114

Bu hatayı alıyorum "Nesne, ObjectStateManager'da bulunamadığı için silinemez."

Benim kodum:

    protected MyEntities sqlEntities;

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

5
Maalesef, kodda kaydı almak ve silmek için farklı veri bağlamı nesnesinin kullanılması sorunu vardı.
Sami

Bunun gibi bir hata var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity);yaşadım : Entity Framework'ün PK
C'ye

Yanıtlar:


156

Bu, varlığın eklenmediği (aynı bağlam örneği tarafından yüklenmediği) anlamına gelir. Bunu dene:

protected MyEntities sqlEntities;

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

1
Teşekkürler Ladislav. Bu, TransactionScope dışında farklı bir bağlamdan çağrılan bir ebeveynden alt verileri silerken devam eden iki bağlam varken bana yardımcı oldu. Üst aramayı kapsam ve aynı bağlam içine taşıdım ve sorunum çözüldü.
dan richardson

1
@Ladislav: .Attach kullanırsam, farklı bir hata alıyorum: "Bir varlık nesnesine IEntityChangeTracker'ın birden çok örneği tarafından başvurulamaz." Bu, silmeyi engelleyen canlı başka nesne örneklerinin olduğu anlamına mı geliyor?
Mat

2
@Matt: Hayır, nesnenizin zaten başka bir bağlama bağlı olduğu anlamına gelir. Aynı anda ikiye eklenemez. Varlığı silmek için orijinal bağlamı kullanmalısınız.
Ladislav Mrnka

@Ladislav: Teşekkürler, bu daha ileriye bakmama yardımcı oldu - nasıl ele alınacağına cevap verecek gibi görünen şu soruyu buldum: Bir nesnenin Varlık Çerçevesinde bir veri bağlamına zaten eklenmiş olup olmadığını kontrol etmek mümkün mü? . Haklısın, benim durumumda sorun bu gibi görünüyor. Hızlı cevap için teşekkürler!
Matt

Hatırlatıcı için teşekkürler, sadece bir kaydı güncellerken eklemiştim, ancak bir kaydı silerken değil.
pinmonkeyiii

60

Ladislav Mrnka'nın cevabına dair sadece küçük bir açıklama (kabul edilen cevap olmalıdır).

Benim gibi, şu formatta kodunuz var:

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

..onra yapmak istediğiniz şey:

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

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

Belki bu apaçık görünebilir , ancak başlangıçta sadece bağlamı değil, uyulacak varlığı da belirtmenin gerekli olduğu bana açık değildi .


1
Bu yaklaşımı kullanıyorum ve istisna alıyorum: "Store update, insert veya delete ifadesi beklenmedik sayıda satırı (0) etkiledi. Varlıklar yüklendikten sonra varlıklar değiştirilmiş veya silinmiş olabilir. ObjectStateManager girişlerini yenileyin."
kat1330

11

Sadece Kjartalıların açıklamasını düzeltmek için:

Sahiptim:

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

Sorun, varlığı elde etmek için kendi yöntemimi (GetProject ()) kullanmam (dolayısıyla varlığı yüklemek için başka bir bağlam kullanmam):

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

Bir çözüm, varlığı aynı bağlam içinde yüklemek için yüklenen varlığı Kjartan'ın belirttiği gibi eklemek olabilir, diğeri benim çözümüm olabilir:

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

Bu sorunun oldukça eski olduğunu biliyorum, ancak birden fazla sınıf / hizmetten kayıtları sildiğimden ve her biri kendi veritabanı bağlantı bağlamını başlattığım için yukarıdakilerin hiçbiri benim için işe yaramadı.

Bunu çözmek için yaptığım şey, ilk oluşturulan bağlamı, veritabanına erişecekleri diğer sınıflara / hizmetlere göndermekti.

Örneğin, benim serviceAbazı kayıtlarını silecek ve çağıracak serviceBve serviceCkayıtlarıyla aynısını yapacaktı.

Daha sonra kayıtlarımı siler serviceAve serviceAto serviceBve üzerinde oluşturulan bağlamı bir parametre olarak iletirim serviceC.


2

Bu kodu yazabilirsiniz:

var x=yourquery.FirstOrDefault(); 

sqlEntities.DeleteObject(x);
sqlEntities.SaveChanges();

1

Yukarıdakilerin hiçbiri işe yaramazsa, şu çözümü deneyebilirsiniz:

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


0

Kaldırmaya çalıştığınız listede nesnenizin bulunduğundan emin olmalısınız, aşağıdaki koşulu koymalısınız

eğer (context.entity.contains (nesneniz))

onu kaldır.

Eşitlik için karmaşık bir koşulunuz varsa, "varlık.içerir" uzantı yöntemi için doğru yolu elde etmek üzere eşitlik koşulunuzu belirlemek için varlık sınıfında eşit yöntemi geçersiz kılmalısınız.


0

Kaldır (Varlık) 'a geçen modelin veritabanı kaydıyla tamamen aynı olduğundan emin olun.

Bazı durumlarda modeli Id veya Tarih gibi bazı alanlar olmadan geçmek mümkündür. form olarak gönderiyorsanız bunları @ html.Hiddenfor içinde tutun.

En iyi yol, kimliği geçmek ve varlığı Bul (Id) yöntemini kullanarak almak ve bunu Kaldır (Varlık) 'a iletmektir

Umarım bu birine yardımcı olur.


0

Bu sorunu anladım ve çözdüm. Aşağıdaki kodu kopyalamanız yeterlidir:

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

0

Benim durumumda bir bağlam vardı, ancak 'AsNoTracking' seçeneğiyle varlığım var

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.