ฉันจะลบหลายแถวใน Entity Framework ได้อย่างไร (โดยไม่ foreach)


305

ฉันกำลังลบหลายรายการจากตารางโดยใช้ Entity Framework ไม่มีคีย์ต่างประเทศ / วัตถุแม่ดังนั้นฉันไม่สามารถจัดการกับ OnDeleteCascade

ตอนนี้ฉันกำลังทำสิ่งนี้:

var widgets = context.Widgets
    .Where(w => w.WidgetId == widgetId);

foreach (Widget widget in widgets)
{
    context.Widgets.DeleteObject(widget);
}
context.SaveChanges();

มันใช้งานได้ แต่ foreach ทำให้ฉันรำคาญ ฉันใช้ EF4 แต่ฉันไม่ต้องการรัน SQL ฉันแค่ต้องการให้แน่ใจว่าฉันจะไม่พลาดอะไรเลย - มันดีเท่าที่จะได้รับใช่ไหม? ฉันสามารถสรุปมันด้วยวิธีการต่อเติมหรือผู้ช่วย แต่ที่ไหนสักแห่งที่เราจะยังคงทำ foreach ใช่มั้ย


1
คุณอาจต้องการทบทวนคำตอบที่ได้รับการยอมรับอีกครั้ง
Eric J.

1
หากคุณต้องการพักนักแสดงบางทีคุณอาจต้องการตรวจสอบคำตอบของฉันที่นี่stackoverflow.com/a/35033286/274589
Adi

คำตอบ:


49

หากคุณไม่ต้องการรัน SQL โดยตรงการเรียกใช้ DeleteObject ในลูปจะเป็นการดีที่สุดที่คุณสามารถทำได้ในวันนี้

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

แม้ว่าคำตอบนั้นสำหรับ 3.5 สำหรับ 4.0 ฉันอาจจะใช้ ExecuteStoreCommand API ใหม่ภายใต้ประทุนแทนที่จะปล่อยลงไปที่ StoreConnection


ExecuteStoreCommand ไม่ใช่วิธีที่เหมาะสม DeleteAllSubmit ทำงานใน linq ไปยัง sql แต่ไม่อยู่ในกรอบงานเอนทิตี ฉันต้องการตัวเลือกเดียวกันในกรอบงานเอนทิตี
Hiral

653

EntityFramework 6 .RemoveRange()ได้ทำนี้บิตง่ายขึ้นด้วย

ตัวอย่าง:

db.People.RemoveRange(db.People.Where(x => x.State == "CA"));
db.SaveChanges();

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

นี่คือ WAAAYYYY เร็วกว่าการตั้งค่าสถานะที่ถูกลบไปยังทุกเอนทิตี!
Jerther

54
แน่นอนว่าคำตอบนี้ง่ายกว่า แต่ประสิทธิภาพก็ไม่ควรยอดเยี่ยม ทำไม? สิ่งที่ doet exatly นี้เป็นเช่นเดียวกับการลบมันในวง foreach มันจะดึงแถวทั้งหมดแล้วลบทีละคนเพียงได้รับคือการบันทึก "DetectChanges จะถูกเรียกครั้งเดียวก่อนที่จะลบหน่วยงานใด ๆ และจะไม่ถูกเรียกอีกครั้ง" ส่วนที่เหลือ เหมือนกันลองใช้เครื่องมือเพื่อดู sql ที่สร้างขึ้น
Anshul Nigam

6
สำหรับช่วงที่มีขนาดใหญ่พอลองทำอะไรสักอย่างใช้ (10,000) แล้ววนซ้ำจนกว่า RemoveRange (... ). Count () == 0.
Eric J.

20
ปัญหาคือพารามิเตอร์อินพุต RemoveRange เป็น IEnumerable ดังนั้นเพื่อดำเนินการลบจะระบุเอนทิตีทั้งหมดและเรียกใช้ 1 ลบแบบสอบถามต่อเอนทิตี
bubi

74

มันดีเท่าที่จะได้รับใช่ไหม? ฉันสามารถสรุปมันด้วยวิธีการต่อเติมหรือผู้ช่วย แต่ที่ไหนสักแห่งที่เราจะยังคงทำ foreach ใช่มั้ย

ใช่แล้วยกเว้นคุณสามารถทำให้เป็นสองซับได้

context.Widgets.Where(w => w.WidgetId == widgetId)
               .ToList().ForEach(context.Widgets.DeleteObject);
context.SaveChanges();

76
คุณกำลังทำ ToList () ซึ่งเอาชนะวัตถุประสงค์ มันแตกต่างจากโซลูชันดั้งเดิมอย่างไร?
lahsrah

3
ฉันมีปัญหาเนื่องจากมีเพียงวิธีการลบในบริบทวัตถุ
Pnct

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

Entity Framework ตามชื่อแนะนำจะทำงานได้ดีที่สุดกับข้อมูลในระดับเอนทิตี การดำเนินการข้อมูลจำนวนมากได้รับการจัดการที่ดีที่สุดโดย procs เก่า ประสิทธิภาพที่ชาญฉลาดนั้นเป็นตัวเลือกที่ดีที่สุดและจะเอาชนะตรรกะของ EF ที่ต้องใช้การวนซ้ำ
Paceman

72
using (var context = new DatabaseEntities())
{
    context.ExecuteStoreCommand("DELETE FROM YOURTABLE WHERE CustomerID = {0}", customerId);
}

แต่คุณจะทำสิ่งนี้กับรายการรหัสได้อย่างไร วิธีนี้ไม่สามารถจัดการ "รายการ" ได้เป็นอย่างดี
JesseNewman19

11
@ JesseNewman19 หากคุณมีรายการของรหัสให้ใช้แล้วอาร์กิวเมนต์ที่สองควรจะเป็นWHERE IN ({0}) String.Join(",", idList)
Langdon

@ Langdon ที่ใช้งานไม่ได้เพราะมันจะส่งคำสั่งไปยัง sql ดังนี้: WHERE IN ("1, 2, 3") ฐานข้อมูลจะพ่นข้อผิดพลาดเนื่องจากคุณผ่านสตริงแทนรายการจำนวนเต็ม
JesseNewman19

ฉันต้องการสร้างคำสั่งเช่นนั้นกับ LINQ สิ่งที่ฉันพบใกล้เคียงที่สุดคือ lib EntityFramework.Extended
Jaider

หากคุณใช้String.Joinคุณอาจต้องใช้string.Formatและส่งสตริง SQL ที่มีอยู่แล้วไปยังคำสั่ง ตราบใดที่รายการของคุณมีจำนวนเต็มจะไม่มีความเสี่ยงในการถูกโจมตีจากการฉีดยา ตรวจสอบคำถามนี้: ฉันจะส่งผ่านอาร์เรย์ไปยังคำสั่ง execute store ได้อย่างไร?
Andrew

50

ฉันรู้ว่ามันค่อนข้างช้า แต่ในกรณีที่มีคนต้องการวิธีแก้ปัญหาง่ายๆสิ่งที่ยอดเยี่ยมคือคุณสามารถเพิ่มส่วนคำสั่งด้วย:

public static void DeleteWhere<T>(this DbContext db, Expression<Func<T, bool>> filter) where T : class
{
    string selectSql = db.Set<T>().Where(filter).ToString();
    string fromWhere = selectSql.Substring(selectSql.IndexOf("FROM"));
    string deleteSql = "DELETE [Extent1] " + fromWhere;
    db.Database.ExecuteSqlCommand(deleteSql);
}

หมายเหตุ: เพิ่งทดสอบกับ MSSQL2008

ปรับปรุง:

วิธีการแก้ปัญหาข้างต้นจะไม่ทำงานเมื่อ EF สร้างคำสั่ง sql พร้อมพารามิเตอร์ดังนั้นนี่คือการอัปเดตสำหรับEF5 :

public static void DeleteWhere<T>(this DbContext db, Expression<Func<T, bool>> filter) where T : class
{
    var query = db.Set<T>().Where(filter);

    string selectSql = query.ToString();
    string deleteSql = "DELETE [Extent1] " + selectSql.Substring(selectSql.IndexOf("FROM"));

    var internalQuery = query.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(field => field.Name == "_internalQuery").Select(field => field.GetValue(query)).First();
    var objectQuery = internalQuery.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(field => field.Name == "_objectQuery").Select(field => field.GetValue(internalQuery)).First() as ObjectQuery;
    var parameters = objectQuery.Parameters.Select(p => new SqlParameter(p.Name, p.Value)).ToArray();

    db.Database.ExecuteSqlCommand(deleteSql, parameters);
}

มันต้องใช้การสะท้อนเล็กน้อย แต่ใช้งานได้ดี


DbContext คืออะไร ฉันถือว่าบริบทกรอบเอนทิตีที่สร้างขึ้นอัตโนมัติของคุณหรือไม่ ฉันไม่มีวิธีที่เรียกว่า Set <T>
Stealth Rabbi

@Stealth: ใช่แล้วมันเป็นบริบทข้อมูล EF ของคุณฉันใช้รหัสก่อน แต่บริบทที่สร้างขึ้นอัตโนมัติควรเหมือนกัน ขออภัยสำหรับคำสั่งที่พิมพ์ผิดควรตั้งค่า <T> () (บริษัท ของฉัน จำกัด การเข้าถึงอินเทอร์เน็ตฉันไม่สามารถวางรหัสได้ต้องพิมพ์ด้วยมือดังนั้น ... ) อัปเดตรหัส :)
Thanh Nguyen

3
นี่เป็นคำตอบเดียวที่ตอบคำถามได้จริง! คำตอบอื่น ๆ จะลบแต่ละรายการทีละรายการไม่น่าเชื่อ
Rocklan

นี่เป็นคำตอบที่ถูกต้องที่สุด จะช่วยให้การลบในลักษณะทั่วไปมากและอย่างถูกต้อง offloads งานไปยังฐานข้อมูลและไม่ C #
JesseNewman19

1
สำหรับโปรแกรมเมอร์ด้านเทคนิคที่น้อยกว่านั้นฉันต้องการอธิบายเพิ่มเติมเกี่ยวกับวิธีการใช้โซลูชันที่ยอดเยี่ยมและทั่วไปนี้เพราะจะช่วยให้ฉันประหยัดเวลาได้ไม่กี่นาที! อย่างต่อเนื่องในความคิดเห็นต่อไป ...
jdnew18

30

สำหรับทุกคนที่ใช้ EF5 สามารถใช้ไลบรารีส่วนขยายต่อไปนี้: https://github.com/loresoft/EntityFramework.Extended

context.Widgets.Delete(w => w.WidgetId == widgetId);

3
มีปัญหาด้านประสิทธิภาพในตารางขนาดใหญ่ไม่สามารถใช้งานได้ในสถานการณ์ของฉัน
โทมัส

@ โทมัสชนิดใดที่คุณสังเกตเห็นว่าการประนีประนอม? ปัญหารุนแรงแค่ไหนและใหญ่แค่ไหนในตาราง? มีใครอีกคนที่สามารถยืนยันได้?
Anestis Kivranoglou

เป็นการเปรียบเทียบที่รวดเร็วกับทางเลือกอื่น ๆ
Jaider

ฉันไม่เห็นDelete()ฟังก์ชันในเอนทิตีของฉันใน EF6
dotNET

context.Widgets.Where(w => w.WidgetId == widgetId).Delete();เป็นวิธีที่ใหม่กว่าด้วย EntityFramework ขยาย
Peter Kerr

11

ยังดูเหมือนว่าจะบ้าที่จะต้องดึงสิ่งใดจากเซิร์ฟเวอร์เพียงเพื่อลบ แต่อย่างน้อยการกลับมาเพียงแค่ ID นั้นผอมกว่าการดึงเอนทิตีแบบเต็ม:

var ids = from w in context.Widgets where w.WidgetId == widgetId select w.Id;
context.Widgets.RemoveRange(from id in ids.AsEnumerable() select new Widget { Id = id });

โปรดระวัง - สิ่งนี้อาจทำให้การตรวจสอบเอนทิตีของเอนทิตี Framework ล้มเหลวเนื่องจากWidgetวัตถุต้นขั้วของคุณมีIdคุณสมบัติเริ่มต้นเท่านั้น วิธีการนี้คือการใช้context.Configuration.ValidateOnSaveEnabled = false(อย่างน้อยใน EF6) สิ่งนี้ปิดใช้งานการตรวจสอบความถูกต้องของ Entity Framework แต่ยังคงทำการตรวจสอบความถูกต้องของฐานข้อมูลเอง
Sammy S.

@SammyS ฉันไม่ได้มีประสบการณ์ดังนั้นจึงไม่สามารถพูดคุยกับรายละเอียดได้ แต่ดูเหมือนว่า EF จะรบกวนการตรวจสอบเมื่อทำการลบแถวอย่างไรก็ตาม
Edward Brey

คุณถูกต้องอย่างแน่นอน ฉันสับสนdeleteกับวิธีแก้ปัญหาที่คล้ายกันสำหรับupdateหน่วยงานไอเอ็นจีโดยไม่ต้องโหลดพวกเขา
Sammy S.

10

EF 6.1

public void DeleteWhere<TEntity>(Expression<Func<TEntity, bool>> predicate = null) 
where TEntity : class
{
    var dbSet = context.Set<TEntity>();
    if (predicate != null)
        dbSet.RemoveRange(dbSet.Where(predicate));
    else
        dbSet.RemoveRange(dbSet);

    context.SaveChanges();
} 

การใช้งาน:

// Delete where condition is met.
DeleteWhere<MyEntity>(d => d.Name == "Something");

Or:

// delete all from entity
DeleteWhere<MyEntity>();

7
สิ่งนี้มีประสิทธิภาพเหมือนกับ db.People.RemoveRange (db.People.Where (x => x.State == "CA")); db.SaveChanges (); ดังนั้นจึงไม่มีประสิทธิภาพเพิ่มขึ้น
ReinierDG

4

สำหรับ EF 4.1

var objectContext = (myEntities as IObjectContextAdapter).ObjectContext;
objectContext.ExecuteStoreCommand("delete from [myTable];");

1
ใช้งานได้ แต่จุดทั้งหมดของการใช้ Entity Framework กำลังมีวิธีเชิงวัตถุในการโต้ตอบกับฐานข้อมูล นี่เป็นเพียงการเรียกใช้แบบสอบถาม SQL โดยตรง
Arturo Torres Sánchez

4

คุณสามารถใช้ไลบรารีส่วนขยายสำหรับการทำเช่น EntityFramework.Extended หรือ Z.EntityFramework.Plus.EF6 มีอยู่ใน EF 5, 6 หรือ Core ไลบรารีเหล่านี้มีประสิทธิภาพที่ยอดเยี่ยมเมื่อคุณต้องลบหรืออัปเดตและใช้ LINQ ตัวอย่างสำหรับการลบ ( แหล่งที่มาบวก ):

ctx.Users.Where(x => x.LastLoginDate < DateTime.Now.AddYears(-2)) .Delete();

หรือ (ที่มาขยาย )

context.Users.Where(u => u.FirstName == "firstname") .Delete();

สิ่งเหล่านี้ใช้คำสั่ง SQL ดั้งเดิมดังนั้นประสิทธิภาพจึงยอดเยี่ยม


จ่าย 600 $ + สำหรับเครื่องกำเนิดไฟฟ้า sql อย่างจริงจัง?
nicolay.anykienko

@ nicolay.anykienko เมื่อฉันใช้มันห้องสมุดนี้ฟรีมีการดำเนินการอื่น ๆ ที่คุณต้องจ่ายใช่มั้ยฉันไม่รู้ว่าคุณต้องจ่ายหรือไม่
UUHHIVS

3

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

ในตัวอย่างนี้ฉันมีสองตารางรายการและรายการมัน ฉันต้องการวิธีที่รวดเร็วในการลบ ListItems ทั้งหมดของรายการที่กำหนด

CREATE TABLE [act].[Lists]
(
    [Id] INT NOT NULL PRIMARY KEY IDENTITY, 
    [Name] NVARCHAR(50) NOT NULL
)
GO
CREATE UNIQUE INDEX [IU_Name] ON [act].[Lists] ([Name])
GO
CREATE TABLE [act].[ListItems]
(
    [Id] INT NOT NULL IDENTITY, 
    [ListId] INT NOT NULL, 
    [Item] NVARCHAR(100) NOT NULL, 
    CONSTRAINT PK_ListItems_Id PRIMARY KEY NONCLUSTERED (Id),
    CONSTRAINT [FK_ListItems_Lists] FOREIGN KEY ([ListId]) REFERENCES [act].[Lists]([Id]) ON DELETE CASCADE
)
go
CREATE UNIQUE CLUSTERED INDEX IX_ListItems_Item 
ON [act].[ListItems] ([ListId], [Item]); 
GO

CREATE PROCEDURE [act].[DeleteAllItemsInList]
    @listId int
AS
    DELETE FROM act.ListItems where ListId = @listId
RETURN 0

ตอนนี้ส่วนที่น่าสนใจในการลบไอเท็มและอัพเดตเฟรมเวิร์กเอนทิตีโดยใช้ส่วนขยาย

public static class ListExtension
{
    public static void DeleteAllListItems(this List list, ActDbContext db)
    {
        if (list.Id > 0)
        {
            var listIdParameter = new SqlParameter("ListId", list.Id);
            db.Database.ExecuteSqlCommand("[act].[DeleteAllItemsInList] @ListId", listIdParameter);
        }
        foreach (var listItem in list.ListItems.ToList())
        {
            db.Entry(listItem).State = EntityState.Detached;
        }
    }
}

รหัสหลักตอนนี้สามารถใช้มันเป็น

[TestMethod]
public void DeleteAllItemsInListAfterSavingToDatabase()
{
    using (var db = new ActDbContext())
    {
        var listName = "TestList";
        // Clean up
        var listInDb = db.Lists.Where(r => r.Name == listName).FirstOrDefault();
        if (listInDb != null)
        {
            db.Lists.Remove(listInDb);
            db.SaveChanges();
        }

        // Test
        var list = new List() { Name = listName };
        list.ListItems.Add(new ListItem() { Item = "Item 1" });
        list.ListItems.Add(new ListItem() { Item = "Item 2" });
        db.Lists.Add(list);
        db.SaveChanges();
        listInDb = db.Lists.Find(list.Id);
        Assert.AreEqual(2, list.ListItems.Count);
        list.DeleteAllListItems(db);
        db.SaveChanges();
        listInDb = db.Lists.Find(list.Id);
        Assert.AreEqual(0, list.ListItems.Count);
    }
}

ขอบคุณสำหรับตัวอย่างที่ดีของการใช้ Stored Procedure และนำไปใช้เป็นส่วนขยายด้วยรหัสการใช้งาน
ล็นการ์สัน

3

หากคุณต้องการลบแถวทั้งหมดของตารางคุณสามารถดำเนินการคำสั่ง sql

using (var context = new DataDb())
{
     context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
}

TRUNCATE TABLE (Transact-SQL) ลบแถวทั้งหมดออกจากตารางโดยไม่ทำการบันทึกการลบแถวแต่ละแถว TRUNCATE TABLE คล้ายกับคำสั่ง DELETE โดยไม่มี WHERE clause; อย่างไรก็ตามตาราง TRUNCATE นั้นเร็วกว่าและใช้ทรัพยากรน้อยลงในระบบและทรานแซคชันธุรกรรม


3
คุณควรพูดถึงว่าคุณไม่สามารถเรียกใช้truncate tableบนตารางที่อ้างถึงโดยข้อ จำกัด ของคีย์ต่างประเทศ (คุณสามารถตัดทอนตารางที่มี foreign key ที่อ้างอิงตัวเอง) เอกสาร MSDN
บรอดแบนด์

2

UUHHIVSเป็นวิธีที่สวยงามและรวดเร็วสำหรับการลบแบบกลุ่ม แต่ต้องใช้ด้วยความระมัดระวัง:

  • การสร้างธุรกรรมอัตโนมัติ: การสืบค้นจะถูกห้อมล้อมด้วยธุรกรรม
  • ความเป็นอิสระของบริบทฐานข้อมูล: การดำเนินการไม่มีส่วนเกี่ยวข้อง context.SaveChanges()

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

var repo = DataAccess.EntityRepository;
var existingData = repo.All.Where(x => x.ParentId == parentId);  

TransactionScope scope = null;
try
{
    // this starts the outer transaction 
    using (scope = new TransactionScope(TransactionScopeOption.Required))
    {
        // this starts and commits an inner transaction
        existingData.Delete();

        // var toInsert = ... 

        // this relies on EntityFramework.BulkInsert library
        repo.BulkInsert(toInsert);

        // any other context changes can be performed

        // this starts and commit an inner transaction
        DataAccess.SaveChanges();

        // this commit the outer transaction
        scope.Complete();
    }
}
catch (Exception exc)
{
    // this also rollbacks any pending transactions
    scope?.Dispose();
}

2

Entity Framework Core

3.1 3.0 2.2 2.1 2.0 1.1 1.0

using (YourContext context = new YourContext ())
{
    var widgets = context.Widgets.Where(w => w.WidgetId == widgetId);
    context.Widgets.RemoveRange(widgets);
    context.SaveChanges();
}

สรุป :

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

ข้อสังเกต :

โปรดทราบว่าหาก System.Data.Entity.Infrastructure.DbContextConfiguration.AutoDetectChangesEnabled ถูกตั้งค่าเป็น true (ซึ่งเป็นค่าเริ่มต้น) DetectChanges จะถูกเรียกหนึ่งครั้งก่อนที่จะลบเอนทิตีใด ๆ และจะไม่ถูกเรียกอีกครั้ง ซึ่งหมายความว่าในบางสถานการณ์ RemoveRange อาจทำงานได้ดีกว่าการโทรออกหลาย ๆ ครั้ง โปรดทราบว่าหากเอนทิตีใด ๆ ที่มีอยู่ในบริบทในสถานะที่เพิ่มแล้ววิธีนี้จะทำให้มันจะถูกแยกออกจากบริบท นี่เป็นเพราะเอนทิตีที่เพิ่มเข้ามานั้นไม่ได้มีอยู่ในฐานข้อมูลซึ่งการพยายามลบมันไม่สมเหตุสมผล


1

คุณสามารถดำเนินการแบบสอบถาม SQL โดยตรงดังนี้

    private int DeleteData()
{
    using (var ctx = new MyEntities(this.ConnectionString))
    {
        if (ctx != null)
        {

            //Delete command
            return ctx.ExecuteStoreCommand("DELETE FROM ALARM WHERE AlarmID > 100");

        }
    }
    return 0;
}

สำหรับการเลือกเราอาจใช้

using (var context = new MyContext()) 
{ 
    var blogs = context.MyTable.SqlQuery("SELECT * FROM dbo.MyTable").ToList(); 
}

เนื่องจาก EF ไม่สนับสนุนการทำแผนที่เงื่อนไขการลบอย่างถูกต้องนี่อาจเป็นทางออกที่ดีที่สุดสำหรับการทำงานให้สำเร็จ
Tony O'Hagan

1

คุณยังสามารถใช้เมธอด DeleteAllOnSubmit ()โดยส่งผลลัพธ์ของคุณในรายการทั่วไปแทนใน var วิธีนี้ foreach ของคุณจะลดโค้ดหนึ่งบรรทัด:

List<Widgets> widgetList = context.Widgets
              .Where(w => w.WidgetId == widgetId).ToList<Widgets>();

context.Widgets.DeleteAllOnSubmit(widgetList);

context.SubmitChanges();

มันอาจยังคงใช้การวนรอบภายในได้


3
ดูเหมือนว่าคุณกำลังเข้าใจผิดในสิ่งที่varเป็น
freedomn-m

1

คำตอบของธานทำงานได้ดีที่สุดสำหรับฉัน ลบระเบียนทั้งหมดของฉันในทริปเซิร์ฟเวอร์เดียว ฉันต่อสู้กับการเรียกวิธีการขยายจริง ๆ แล้วคิดว่าฉันจะแบ่งปันของฉัน (EF 6):

ฉันเพิ่มวิธีการขยายไปยังคลาสตัวช่วยในโครงการ MVC ของฉันและเปลี่ยนชื่อเป็น "RemoveWhere" ผมฉีด dbContext เข้าควบคุมของฉัน usingแต่คุณยังสามารถทำ

// make a list of items to delete or just use conditionals against fields
var idsToFilter = dbContext.Products
    .Where(p => p.IsExpired)
    .Select(p => p.ProductId)
    .ToList();

// build the expression
Expression<Func<Product, bool>> deleteList = 
    (a) => idsToFilter.Contains(a.ProductId);

// Run the extension method (make sure you have `using namespace` at the top)
dbContext.RemoveWhere(deleteList);

สิ่งนี้สร้างคำสั่งลบเดียวสำหรับกลุ่ม


0

EF 6. =>

var assignmentAddedContent = dbHazirBot.tbl_AssignmentAddedContent.Where(a =>
a.HazirBot_CategoryAssignmentID == categoryAssignment.HazirBot_CategoryAssignmentID);
dbHazirBot.tbl_AssignmentAddedContent.RemoveRange(assignmentAddedContent);
dbHazirBot.SaveChanges();

0

ดีที่สุด: in EF6 => .RemoveRange()

ตัวอย่าง:

db.Table.RemoveRange(db.Table.Where(x => Field == "Something"));

14
สิ่งนี้แตกต่างจากคำตอบของ Kyle อย่างไร

-1

ดูคำตอบ 'รหัสที่ชื่นชอบบิต' ที่ใช้งานได้

นี่คือวิธีที่ฉันใช้:

     // Delete all rows from the WebLog table via the EF database context object
    // using a where clause that returns an IEnumerable typed list WebLog class 
    public IEnumerable<WebLog> DeleteAllWebLogEntries()
    {
        IEnumerable<WebLog> myEntities = context.WebLog.Where(e => e.WebLog_ID > 0);
        context.WebLog.RemoveRange(myEntities);
        context.SaveChanges();

        return myEntities;
    }

1
คำตอบของคุณแตกต่างจากuser1308743อย่างไร
Sergey Berezovskiy

ฉันแค่แบ่งปันตัวอย่างการทำงาน อะไรก็ตามที่ฉันสามารถทำได้เพื่อตอบแทนความช่วยเหลือที่ฉันได้รับที่นี่
Brian Quinn

-3

ใน EF 6.2 นี่ทำงานได้อย่างสมบูรณ์ส่งการลบไปยังฐานข้อมูลโดยตรงโดยไม่ต้องโหลดเอนทิตีก่อน:

context.Widgets.Where(predicate).Delete();

ด้วยภาคแสดงความแน่นอนมันค่อนข้างตรงไปตรงมา:

context.Widgets.Where(w => w.WidgetId == widgetId).Delete();

และถ้าคุณต้องการเพรดิเคตแบบไดนามิกให้ดูที่LINQKit (มีแพ็คเกจ Nuget) สิ่งนี้จะใช้ได้ในกรณีของฉัน:

Expression<Func<Widget, bool>> predicate = PredicateBuilder.New<Widget>(x => x.UserID == userID);
if (somePropertyValue != null)
{
    predicate = predicate.And(w => w.SomeProperty == somePropertyValue);
}
context.Widgets.Where(predicate).Delete();

1
เมื่อใช้ EF 6.2 ดิบจะไม่สามารถทำได้ บางทีคุณกำลังใช้Z.EntityFramework.Plusหรือสิ่งที่คล้ายกัน ( entityframework.net/batch-delete )
Sammy S.

อันแรกคือวัตถุดิบ EF 6.2 และหาได้ อย่างที่สองคืออย่างที่ฉันพูดโดยใช้ LINQKit
Vladimir

1
อืมฉันหาวิธีนี้ไม่เจอ คุณสามารถตรวจสอบว่าคลาสใดและเนมสเปซวิธีนี้อยู่ที่ใด?
Sammy S.

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