Không thể xóa đối tượng vì nó không được tìm thấy trong ObjectStateManager


114

Tôi nhận được lỗi này "Không thể xóa đối tượng vì nó không được tìm thấy trong ObjectStateManager."

Mã của tôi là:

    protected MyEntities sqlEntities;

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

5
Xin lỗi, đã xảy ra sự cố trong mã mà đối tượng văn bản dữ liệu khác nhau đã được sử dụng để tìm nạp và xóa bản ghi.
Sami

Tôi đã gặp một lỗi như sau: var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity);Tôi đang cố gắng tạo một thực thể giả với PK của nó được đặt chính xác, với hy vọng rằng Entity Framework sẽ gọi DeleteObject dựa trên PK
C. Tewalt

Câu trả lời:


156

Nó có nghĩa là thực thể đó không được đính kèm (nó không được tải bởi cùng một phiên bản ngữ cảnh). Thử cái này:

protected MyEntities sqlEntities;

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

1
Cảm ơn Ladislav. Điều này đã giúp tôi khi tôi gặp phải hai bối cảnh khi xóa dữ liệu con khỏi nguồn gốc - dữ liệu này được gọi từ một ngữ cảnh khác, bên ngoài TransactionScope. Đã chuyển cuộc gọi cha bên trong phạm vi và cùng ngữ cảnh và vấn đề của tôi đã được giải quyết.
dan richardson

1
@Ladislav: Nếu tôi sử dụng .Attach, tôi gặp lỗi khác: "Một đối tượng thực thể không thể được tham chiếu bởi nhiều phiên bản IEntityChangeTracker." Nó có nghĩa là đã có các cá thể đối tượng khác còn sống ngăn cản việc xóa?
Matt

2
@Matt: Không có nghĩa là đối tượng của bạn đã được gắn vào một ngữ cảnh khác. Nó không thể được gắn vào hai cùng một lúc. Bạn nên sử dụng ngữ cảnh ban đầu để xóa thực thể.
Ladislav Mrnka

@Ladislav: Cảm ơn bạn, điều đó đã giúp tôi tìm kiếm xa hơn - Tôi tìm thấy câu hỏi này dường như trả lời cách giải quyết nó: Có thể kiểm tra xem một đối tượng đã được đính kèm với ngữ cảnh dữ liệu trong Entity Framework chưa? . Bạn nói đúng, đây có vẻ là vấn đề trong trường hợp của tôi. Cảm ơn vì sớm phản hồi!
Matt,

Cảm ơn vì lời nhắc, tôi đã đính kèm nó khi chỉ cập nhật bản ghi, nhưng không phải khi tôi xóa bản ghi.
pinmonkeyiii

60

Chỉ là một lời giải thích nhỏ về câu trả lời của Ladislav Mrnka (nên là câu trả lời được chấp nhận).

Nếu giống như tôi, bạn có mã ở định dạng như thế này:

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

..thì đây là những gì bạn muốn làm:

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

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

Có lẽ điều này có vẻ hiển nhiên, nhưng ban đầu tôi không rõ rằng cần phải chỉ định thực thể để phù hợp chứ không chỉ ngữ cảnh .


1
Tôi sử dụng phương pháp này và nhận được ngoại lệ: "Câu lệnh cập nhật, chèn hoặc xóa lưu trữ ảnh hưởng đến một số hàng không mong muốn (0). Các thực thể có thể đã bị sửa đổi hoặc xóa kể từ khi các thực thể được tải. Làm mới các mục nhập ObjectStateManager."
kat1330

11

Chỉ để điều chỉnh theo lời giải thích của Kjartans:

Tôi đã có:

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

Vấn đề là tôi đã sử dụng phương thức của riêng mình (GetProject ()) để lấy thực thể (do đó sử dụng ngữ cảnh khác để tải thực thể):

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

Một giải pháp có thể là đính kèm thực thể đã tải như trạng thái Kjartan, một giải pháp khác có thể là giải pháp của tôi, để tải thực thể trong cùng ngữ cảnh:

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

Tôi biết câu hỏi này khá cũ nhưng không câu nào ở trên phù hợp với tôi vì tôi đã xóa các đăng ký khỏi nhiều hơn một lớp / dịch vụ và mỗi người trong số họ đang khởi tạo ngữ cảnh kết nối cơ sở dữ liệu của riêng mình.

Những gì tôi đã làm để giải quyết nó là gửi ngữ cảnh được tạo đầu tiên đến phần còn lại của các lớp / dịch vụ sẽ truy cập cơ sở dữ liệu.

Ví dụ: tôi serviceAsẽ xóa một số đăng ký của nó và gọi serviceBserviceC làm điều tương tự với các đăng ký của họ.

Sau đó, tôi sẽ xóa các đăng ký của mình trên đó serviceAvà chuyển dưới dạng một tham số mà ngữ cảnh được tạo trên serviceAđến serviceBserviceC.


2

Bạn có thể viết mã này:

var x=yourquery.FirstOrDefault(); 

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

1

Trong trường hợp không có cách nào ở trên hiệu quả, bạn có thể thử giải pháp này:

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


0

Bạn nên chắc chắn rằng đối tượng của bạn đang tồn tại trong danh sách bạn đang cố gắng loại bỏ, bạn nên đặt điều kiện sau

if (context.entity.contains (đối tượng của bạn))

xóa nó.

nếu bạn có một điều kiện phức tạp cho sự bình đẳng, bạn nên ghi đè phương thức bằng trong lớp thực thể để đặt điều kiện của bạn cho bằng nhau, để có được cách phù hợp cho phương thức mở rộng "entity.contains"


0

Đảm bảo rằng mô hình truyền vào Loại bỏ (Thực thể) giống hệt như bản ghi cơ sở dữ liệu.

Đôi khi có thể chuyển mô hình với một số trường như Id hoặc Date. giữ chúng thành @ html.Hiddenfor nếu bạn đăng dưới dạng biểu mẫu.

Cách tốt nhất là chuyển ID và lấy đối tượng bằng phương pháp Tìm (Id) và chuyển nó cho Xóa (Thực thể)

Hy vọng điều này sẽ giúp ai đó.


0

Tôi nhận được vấn đề này và giải quyết nó. Chỉ cần sao chép mã dưới đây:

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

0

Trong trường hợp của tôi, có một ngữ cảnh, nhưng tôi có thực thể với tùy chọn 'AsNoTracking'

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.