วิธีการลบออบเจ็กต์ด้วย id ด้วยเอนทิตีเฟรมเวิร์ก


110

สำหรับฉันแล้วดูเหมือนว่าฉันต้องดึงข้อมูลวัตถุก่อนที่จะลบด้วยกรอบเอนทิตีดังต่อไปนี้

var customer = context.Customers.First(c => c.Id == 1);

context.DeleteObject(customer);

context.Savechanges();

ดังนั้นฉันต้องตีฐานข้อมูลสองครั้ง มีวิธีที่ง่ายกว่านี้ไหม


j.mp/f0x0Bhคือคำตอบของคุณ นี่เป็นวิธีที่ดีและใช้กันทั่วไป
BritishDeveloper

คำตอบ:


103

ใน Entity Framework 6 Removeการดำเนินการลบคือ นี่คือตัวอย่าง

Customer customer = new Customer () { Id = id };
context.Customers.Attach(customer);
context.Customers.Remove(customer);
context.SaveChanges();

17
ทำไมAttach? ทำไมไม่เพียงRemoveและSaveChanges?
runeks

3
คุณต้องแนบเอนทิตีของคุณในบริบทเพราะหากคุณไม่ทำเช่นนั้นคุณจะได้รับข้อผิดพลาดขณะนำออก EF สามารถลบเอนทิตีในบริบทนี้เท่านั้น
Pierre-Luc

4
@runeks ตามคู่มือเอนทิตีต้องมีอยู่ในบริบทก่อนที่จะดำเนินการลบได้ ดูที่นี่docs.microsoft.com/en-us/dotnet/api/…
dwkd

1
ฉันไม่ได้ใช้ไฟล์แนบและมันก็สบายดี
ILIAS M. DOLAPO

58

เช่นเดียวกับ @Nix ที่มีการเปลี่ยนแปลงเล็กน้อยที่จะพิมพ์อย่างรุนแรง:

หากคุณไม่ต้องการสอบถามเพียงแค่สร้างเอนทิตีแล้วลบออก

                Customer customer = new Customer () { Id = id };
                context.Customers.Attach(customer);
                context.Customers.DeleteObject(customer);
                context.SaveChanges();

7
ไม่สมบูรณ์แบบเนื่องจากจะมีข้อยกเว้นหากอ็อบเจ็กต์หายไป: "DbUpdateConcurrencyException: คำสั่งการอัปเดตการแทรกหรือการลบที่เก็บมีผลต่อจำนวนแถวที่ไม่คาดคิด (0)" ฉันต้องการให้เพิกเฉยต่อสิ่งนี้เช่นเดียวกับคำสั่ง DELETE
Dunc

ขออภัยสิ่งนี้ทำให้เกิดการตรวจสอบความถูกต้องซึ่งไม่จำเป็นและคาดหวังเสมอ!
Hamed Zakery Miab

33

คำถามที่คล้ายกันที่นี่

ด้วย Entity Framework จะมีEntityFramework-Plus (ไลบรารีส่วนขยาย)
พร้อมใช้งานบน NuGet จากนั้นคุณสามารถเขียนสิ่งที่ต้องการ:

// DELETE all users which has been inactive for 2 years
ctx.Users.Where(x => x.LastLoginDate < DateTime.Now.AddYears(-2))
     .Delete();

นอกจากนี้ยังมีประโยชน์สำหรับการลบจำนวนมาก


39
มันท้าทายเหตุผลที่ตอนนี้ยังไม่ได้เป็นส่วนหนึ่งของไลบรารีหลักของ EF
nathanchere

1
@FerretallicA - เห็นด้วย
acarlon

2
วิธีนี้เป็นการใช้งานที่ล้าสมัย: context.Users.Where (user => user.Id == id) .Delete ();
Manuel

ใช้ไม่ได้กับ Azure SQL DataWarehouse เนื่องจากมีข้อผิดพลาด "ขณะนี้ไม่สนับสนุนคำสั่ง FROM ในคำสั่ง DELETE" แต่ SQL ดิบเช่นเดียวกับในคำตอบของ Jonik ใช้งานได้
Michael Freidgeim

1
context.SaveChanges () จำเป็นหรือไม่
Tomas Kubes

23

หากคุณไม่ต้องการสอบถามเพียงแค่สร้างเอนทิตีแล้วลบออก

Customer customer  = new Customer() {  Id = 1   } ; 
context.AttachTo("Customers", customer);
context.DeleteObject(customer);
context.Savechanges();

6

ฉันใช้รหัสต่อไปนี้ในหนึ่งในโครงการของฉัน:

    using (var _context = new DBContext(new DbContextOptions<DBContext>()))
    {
        try
        {
            _context.MyItems.Remove(new MyItem() { MyItemId = id });
            await _context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
            if (!_context.MyItems.Any(i => i.MyItemId == id))
            {
                return NotFound();
            }
            else
            {
                throw ex;
            }
        }
    }

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

[ฉันใช้รหัสนี้ในโครงการ MVC .Net Core / .Net Core ที่มี Entity Framework Core]


2

การสืบค้น Raw sql เป็นวิธีที่เร็วที่สุดที่ฉันคิดว่า

public void DeleteCustomer(int id)
{
   using (var context = new Context())
   {
      const string query = "DELETE FROM [dbo].[Customers] WHERE [id]={0}";
      var rows = context.Database.ExecuteSqlCommand(query,id);
      // rows >= 1 - count of deleted rows,
      // rows = 0 - nothing to delete.
   }
}

19
สิ่งนี้เอาชนะวัตถุประสงค์ของการใช้ฟังก์ชันอ็อบเจ็กต์ที่พิมพ์อย่างรุนแรงใน EF
LawMan

4
นี่เป็นการประนีประนอมเงินสดประจำตัวของ EF หลังจากนี้ EF จะยังคงกลับมาหาคุณที่ถูกลบไปแล้ว
epox

1
ทำงานร่วมกับ Azure SQL DataWarehouse เมื่อโซลูชันอื่นไม่ทำ
Michael Freidgeim

1
หากคุณกำลังทำสิ่งนี้คุณอาจไม่ได้ใช้ ORM เช่นกัน ฉันคิดว่าสิ่งนี้จะทำให้ EF cache ลดลง
Storm Muller

ลักษณะนี้เสี่ยงต่อการโจมตี SQL Injection ในตัวอย่างเฉพาะนี้คุณได้รับการป้องกันเนื่องจากตัวแปรเป็นจำนวนเต็ม แต่อย่าใช้รูปแบบนี้กับตัวแปรสตริง
thelem

2

คำตอบของ dwkd ส่วนใหญ่ใช้ได้กับฉันในหลักของ Entity Framework ยกเว้นเมื่อฉันเห็นข้อยกเว้นนี้:

InvalidOperationException: ไม่สามารถติดตามอินสแตนซ์ของประเภทเอนทิตี "ลูกค้า" ได้เนื่องจากอินสแตนซ์อื่นที่มีค่าคีย์เดียวกันสำหรับ {'Id'} ถูกติดตาม เมื่อแนบเอนทิตีที่มีอยู่ตรวจสอบให้แน่ใจว่ามีการแนบอินสแตนซ์เอนทิตีเดียวที่มีค่าคีย์ที่กำหนดเท่านั้น พิจารณาใช้ 'DbContextOptionsBuilder.EnableSensitiveDataLogging' เพื่อดูค่าคีย์ที่ขัดแย้งกัน

เพื่อหลีกเลี่ยงข้อยกเว้นฉันอัปเดตรหัส:

Customer customer = context.Customers.Local.First(c => c.Id == id);
if (customer == null) {
    customer = new Customer () { Id = id };
    context.Customers.Attach(customer);
}
context.Customers.Remove(customer);
context.SaveChanges();

2

รุ่นที่เล็กกว่า (เมื่อเทียบกับรุ่นก่อนหน้า):

var customer = context.Find(id);
context.Delete(customer);
context.SaveChanges();

โปรดระบุบริบทของข้อมูลโค้ดนี้และอาจมีคำอธิบายว่ามันทำอะไรได้ดีกว่าคำตอบอื่น ๆ ในทศวรรษที่ผ่านมา
miken32

2

คำตอบนี้นำมาจากหลักสูตรของ Scott Allen ที่มีชื่อว่า ASP.NET MVC 5 Fundamentals ฉันคิดว่าฉันจะแบ่งปันเพราะฉันคิดว่ามันง่ายกว่าเล็กน้อยและเข้าใจง่ายกว่าคำตอบใด ๆ ในที่นี้ นอกจากนี้โปรดสังเกตตาม Scott Allen และการฝึกอบรมอื่น ๆ ที่ฉันได้ทำ find method เป็นวิธีที่เหมาะสมที่สุดในการดึงทรัพยากรจากฐานข้อมูลที่สามารถใช้การแคชได้หากมีการดึงข้อมูลไปแล้ว ในรหัสนี้คอลเลกชันหมายถึง DBSet ของวัตถุ วัตถุสามารถเป็นประเภทวัตถุทั่วไป

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