2013-12-10 36 views
2

我試圖在IEnumerable中搜索特定記錄(使用謂詞)。如果該記錄不存在,我想返回第一條記錄。如果那也不存在,我只想要null。我目前使用LINQ FirstOrDefault帶謂詞,如果找不到只是FirstOrDefault

var category = categories.FirstOrDefault(
    c => c.Category == "C") ?? 
    category.FirstOrDefault(); 

ReSharper的

給我一個警告(IEnumerable的可能的多個枚舉)。警告告訴我,我的sql語句可能會執行兩次。一次嘗試找到「C」類別,並再次獲得第一條記錄。如果我首先使用categories.ToList()將類別轉換爲列表,警告將消失。但是如果類別包含大量記錄,那可能會很慢。

有沒有更好的方法來做到這一點?或者我應該忽略這個警告?

+0

如果你想在代碼*中對任意'IEnumerable' *做到這一點,我會建議一個自定義的擴展方法;但考慮到這些項目來自SQL服務器,如果您希望在不重複所有記錄的情況下執行此操作,則需要在數據庫服務器上執行此操作。我認爲不太可能有一組可以自動翻譯的LINQ方法,所以我認爲這是一個sproc。 – AakashM

回答

1

ReSharper的警告,更是一個消息,說「想想你在做什麼」,而不是「你做錯了」。

您的解決方案並不壞,但這一切都取決於情況。

在生產中,該類別不存在多久?這是一種罕見的情況,然後保持原樣。 要考慮的另一件事是執行此代碼的頻率。它是一天一次,還是每秒十次? 它更像第一個?保持原樣。

否則,微型優化可能是有益的。像Seyana這樣的解決方案可能會工作,或者你可以用Take(1)重寫查詢爲union(),所以只有一個查詢將被髮送到SQL Server;但這並不意味着兩個查詢都不會被數據庫引擎執行。

性能分析將爲您提供哪種解決方案最快或使用最少資源的答案。

1

如果您真的擔心性能,FirstOrDefault是O(n)。 如果第一個查詢爲空,則只會執行第二個查詢。 你可以嘗試使用.Any(謂詞)。 First()適合嘗試抓住哪一個可能更適合你的情況。

儘管如此,你並不需要擔心性能優化,直到它成爲問題。

1

如果你在你的類別表中的列,它是連續的,你可以做這樣的事情:

var category = categories.Where(c => c.SomeSequentialId == 1 || c.Category == "C") 
.OrderByDescending(c => c.SomeSequentialId) 
.FirstOrDefault();