2012-03-29 260 views
2

我有一個名爲Entry的實體連接到多個TimeWindows。我想清除所有時間窗口,然後添加新窗口。起初我想:刪除實體框架中的所有相關實體

target.TimeWindows.Clear(); 

但是這並沒有真正刪除,只有試圖刪除關係,這導致了異常,因爲有來自TimeWindows到入口外鍵。後來我想我應該這樣做:

foreach (var tw in target.TimeWindows) 
    context.DeleteObject(tw); 

但這拋出一個異常,以及,因爲收藏是在foreach語句內修改。所以我想這個:

while (target.TimeWindows.Count > 0) 
    context.DeleteObject(target.TimeWindows.Last()); 

但現在我有點擔心使用Count財產,因爲這可能導致被執行的SQL SELECT COUNT聲明。可以?如果是,我如何刪除實體框架中的所有時間窗口?

+1

不,「Count」不會觸發數據庫上的「SELECT COUNT」,這更糟糕:-)。它將執行'SELECT * FROM TimeWindows WHERE TargetId = @ P0'並對內存集合進行計數。 – Steven 2012-03-29 09:49:42

+0

哦,我的上帝!那麼你的建議是什麼?! – Rafid 2012-03-29 12:42:03

+2

當你想刪除一個實體時,它應該首先被加載到內存中。所有的O/RM工具都是這樣工作的。實體框架也不例外。如果性能太低,請編寫一個執行刪除操作的存儲過程。 – Steven 2012-03-29 13:31:54

回答

3

只有在啓用延遲加載並且該屬性尚未加載時,對導航屬性的調用計數纔會導致選擇。因此,第一個電話可能會導致類似的情況:

SELECT * FROM TimeWindows WHERE TargetId = @targetId 

並且所有計數評估將僅在加載的數據上執行。

你也可以利用這一點避免了第二個例外:

foreach (var tw in target.TimeWindows.ToList()) 
    context.DeleteObject(tw); 

或者你可以改變你的數據庫和模型來支持identifying relation(FK於母公司的意志成爲TimeWindow的PK的一部分),在這種情況下,你的第一個代碼片段將起作用。

+0

但執行ToList()意味着獲取所有時間窗口,對吧?!那麼,如果這是正確的,那麼它實際上更糟糕:-) – Rafid 2012-03-29 12:42:34

+0

在SQL中,我真的可以執行一個語句並刪除所有的時間窗口,這就像'DELETE * FROM TimeWindows WHERE EntryId = ...'那麼是否有可能在實體框架中做到這一點? – Rafid 2012-03-29 12:43:47

+0

執行'ToList'只會取一次數據。批量刪除是不可能沒有[小黑客](http://stackoverflow.com/questions/9776964/what-is-the-recommended-practice-to-update-or-delete-multiple-entities-in-entity/9777017 #9777017)但使用此方法時,數據庫中執行的更改不會反映在您的上下文中。 – 2012-03-29 13:06:27