[英]Lambda expressions order by and take issue
我有一個帶有COLOURS
類類型的IQueryable
列表
IQueryable<COLOURS> renkler = dbcontext.colours.Select(s=>new COLOURS{ ....
我想得到隨機的2行,我使用這個代碼塊來做到這一點:
renkler.OrderBy(o => Guid.NewGuid()).Take(2);
我想要2行,但有時會得到3行或5行:
Take(2)
不起作用 - 問題是什么?
我檢查時發現了一些東西
var result = NewProducts().OrderBy(o => Guid.NewGuid()).Take(2);
int result_count = result.Count(); //This value is 2 :D
//but ToList() result 5 :D
整個方法:
public IQueryable<COLOURS> NewProducts()
{
DateTime simdi = DateTime.Now;
DateTime simdi_30 = DateTime.Now.AddDays(-30);
var collection_products = DefaultColours()
.Where(w => ((w.add_date.Value >= simdi_30 && w.add_date.Value <= simdi) || w.is_new == true))
.OrderByDescending(o => o.add_date).Take(200)
.Select(s => new COLOURS
{
colour_code = s.colour_code,
model_code = s.products.model_code,
sell_price = (decimal)s.sell_price,
market_price = (decimal)s.market_price,
is_new = (bool)s.is_new,
product_id = (int)s.product_id,
colour_name = s.name,
product_name = s.products.name,
description = s.products.description,
img_path = s.product_images.FirstOrDefault(f => f.is_main == true).img_path,
category_id = (int)s.category_relations.FirstOrDefault().category_id,
display_order = (short)s.display_order,
section_id = (int)s.products.section_id,
stock_amount = s.pr_sizes.Where(w => w.is_active == true && w.quantity >= 0).Count() > 0 ? (int)s.pr_sizes.Where(w => w.is_active == true && w.quantity >= 0).Sum(s2 => s2.quantity) : 0,
section_name = s.products.pr_sections.name,
});
return collection_products;
}
public IQueryable<COLOURS> RandomNewProducts(int n)
{
var result = NewProducts().OrderBy(o => Guid.NewGuid()).Take(n);
int result_count = result.Count(); //2
//When I run this method it's getting 5 rows
return result;
}
這對您來說可能沒有解決方案,但很難用多行代碼和圖像格式化注釋。
我很確定這是您的數據提供商的問題。 也許這個組件沒有Take()
它應該的方式實現Take()
。
我試圖重建你的星座,但我沒有使用任何IQueryable
提供程序,而是使用500個對象構建了一個List<>
,並在其上調用了AsQueryable()
來滿足方法簽名。
public static IQueryable<COLOURS> DefaultColours()
{
const int COUNT = 500;
List<COLOURS> x = new List<COLOURS>();
var startDate = DateTime.Today.AddDays(-1 * (int)(COUNT / 2));
// add 500 date values, and use the date and any random bool value
for (int i = 0; i < COUNT; i++)
x.Add(new COLOURS() { add_date = startDate.AddDays(i), is_new = i % 3 == 0 });
return x.AsQueryable();
}
但是當我這樣做時, Take()
方法總是每次返回兩個(不同的)項目 - 正如任何人所期望的那樣:
這可能是由於o => Guid.NewGuid()lambda。
排序算法需要一個與每個元素相關聯的唯一鍵。 調用Guid.NewGuid()意味着任何給定元素都可以有多個與之關聯的鍵,具體取決於它何時被調用。 Linq試圖在集合上如何操作機會主義,因此這可能導致例如最低的兩個元素在排序操作期間突然不再是最低的兩個元素。
考慮嘗試對隨機整數列表進行排序,每次排序算法嘗試檢索這些整數時,這些整數隨機變化。 唯一可行的方法是,如果排序算法提供了一次保證調用鍵函數,並且只為每個元素調用一次。
關於OrderBy的文檔沒有說明是否允許排序算法為每個元素多次調用鍵函數,因此最好假設最壞的情況,除非你能證明不是這樣。
作為一種(希望)簡單的測試方法,如果你可以暫時將隨機密鑰作為COLOR對象的持久元素包含,以便在排序過程中順序不變,那么.Take()應該完全按預期工作。
此外,Guid.NewGuid()並不快,所以將臨時測試轉換為為每個對象使用更多內存的永久解決方案也可以提高代碼的速度。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.