2012-01-06 31 views
0

我有以下查詢:從DB(LINQ查詢)返回隨機對象

Banner banner = Database.Banners.Where(b => b.IsPublish.Value && 
     b.Category.Value == (int) CategoryBanner.Banner && 
     b.PeriodShowCountAlready < b.PeriodShowCount || 
     b.ShowNext < DateTime.Now).Take(1).FirstOrDefault(); 

我只檢索一個記錄。假設在DB 3記錄中滿足該查詢,LINQ將始終返回相同的記錄。我想要那個返回的隨機記錄,我該怎麼做?

+2

http://stackoverflow.com/questions/648196/random-row-from-linq-to-sql – 2012-01-06 08:46:18

+1

在'。取(1).FirstOrDefault()''的。取(1)'部分完全是多餘的。 – spender 2012-01-06 08:54:45

回答

3

根據您的數據庫上,這可能工作:

var banners = Database.Banners.Where(b => b.IsPublish.Value && 
     b.Category.Value == (int) CategoryBanner.Banner && 
     b.PeriodShowCountAlready < b.PeriodShowCount || 
     b.ShowNext < DateTime.Now); 

然後就跳過隨機數的橫幅...

var skip = new Random().Next(banners.Count() - 1); 
var banner = banners.Skip(skip).FirstOrDefault(); 

正如Amar指出的那樣,這種方法不夠理想,因爲它導致兩次到達數據庫。根據我自己的經驗分析,往返另一臺服務器的成本通常要比執行簡單的SQL語句要多得多。

那麼,有什麼選擇?

  • 獲取整個集合,並在本地選擇一個隨機橫幅。這不是最優的,因爲這個集合可能非常大。如果你知道該設置很小(少於1000條沒有二進制字段的記錄[如橫幅圖像],或總計小於10k應該可以忽略不計)

  • 詢問數據庫中有多少個對象,並且然後詢問數據庫中的第n個對象。這很糟糕,因爲它會導致兩次旅行。

  • 使數據庫盡一切努力,這使得ORM的舒適性和手動編寫存儲過程。爲此,您可以按參數順序使用newid()[on sql server],並且所有內容都很快且很好,但是您必須在服務器上執行此操作,而不是在C#應用程序中執行此操作。

+0

這很有趣。好一個:) – 2012-01-06 09:19:02

2

更新: 在重複問題的(更好的)answer提供Skip一個例子。這個好處是空的列表處理。此外,這個答案討論了大型結果集的問題,這些問題在我的解決方案中將無法很好地處理......

您可以從db中返回多個結果集,並從結果中選擇一個隨機條目。

List<Banner> list = Database.Banners.Where(b => b.IsPublish.Value && 
     b.Category.Value == (int) CategoryBanner.Banner && 
     b.PeriodShowCountAlready < b.PeriodShowCount || 
     b.ShowNext < DateTime.Now).Take(10).ToList(); 

Random r = new Random(); 
Banner banner = list.Count == 0 ? null : list[r.Next(0, list.Count)]; 
+2

但是,假設OP不是從前10個結果中隨機抽取一行,而是從一組100萬個結果中選擇一個呢?這是相當多的不必要的數據。 – spender 2012-01-06 08:56:54

0

獲取所有記錄,並做他們隨機

試着這樣做:

var records = Database.Banners.Where(b => b.IsPublish.Value && 
b.Category.Value == (int) CategoryBanner.Banner && 
b.PeriodShowCountAlready < b.PeriodShowCount || 
b.ShowNext < DateTime.Now).ToList(); 
var random = new Random(); 
var count = random.Next(records.Count - 1); 
Banner banner = records[count]; 
+0

「返回值的範圍通常包含零但不是maxValue」,所以使用'random.Next(records.Count - 1)'永遠不會爲最後一項創建索引。另外,IQueryable支持索引運算符嗎?我不這麼認爲。 – spender 2012-01-06 08:53:12

+0

這個例子實際上沒有什麼問題,除了-1以外,如果你只需要一個,你可能不想獲取所有的橫幅。@spender - 注意記錄是ToList() - ed。 – Gleno 2012-01-06 08:57:12

+0

忘記ToList的結果。 IQueryable支持Count()雖然 – 2012-01-06 08:58:02