Lambda表达式按顺序排列并采取问题

时间:2016-01-08 10:27:24

标签: c# entity-framework linq lambda

我有一个IQueryable列表COLOURS类类型

IQueryable<COLOURS> renkler = dbcontext.colours.Select(s=>new COLOURS{ .... 

我想获得随机的2行,我正在使用此代码块来执行此操作:

renkler.OrderBy(o => Guid.NewGuid()).Take(2);

我想要2行,但有时需要3行或5行:

enter image description here

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;
}

2 个答案:

答案 0 :(得分:2)

这可能不是你的解决方案,但很难用多行代码和图像格式化评论。

我很确定这是您的数据提供商的问题。也许这个组件没有按照它应该的方式实现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()方法每次都会返回两个(不同的)项目 - 正如任何人所期望的那样:

N4094

答案 1 :(得分:0)

这可能是由于o =&gt; Guid.NewGuid()lambda。

排序算法需要一个与每个元素绑定的唯一键。调用Guid.NewGuid()意味着任何给定元素都可以有多个与之关联的键,具体取决于它何时被调用。 Linq试图对它如何在集合上运行产生机会主义,因此这可能导致例如在排序操作期间,最低的两个元素突然不再是最低的两个元素。

考虑尝试对随机整数列表进行排序,每次排序算法尝试检索这些整数时,这些整数随机变化。唯一可行的方法是,排序算法可以保证为每个元素调用一次键功能一次。

关于OrderBy的文档没有说明是否允许排序算法为每个元素多次调用键函数,所以最好假设最坏的情况,除非你能证明不是这样。

作为一种(希望)简单的测试方法,如果你可以暂时将随机密钥作为COLOR对象的持久元素包含,以便在排序过程中顺序不变,那么.Take()应该开始完全正常工作意。

此外,Guid.NewGuid()并不快,因此将临时测试转换为对每个对象使用更多内存的永久解决方案也可以提高代码的速度。