查询时Shuffle产品列表

本文关键字:产品列表 Shuffle 查询 | 更新日期: 2023-09-27 18:10:55

我在数据库中有一个产品和类别表:

Products有以下几列:ProductId, ProductName, Description, Path, Name, URL, CategoryId, Active

Category有以下列:被标记,CategoryName

我写了一个LINQ语句来查询数据库并获取相关类别的产品。查询工作正常。

public IQueryable<Product> GetProducts(
                     [QueryString("id")] int? categoryId,
                     [RouteData] string categoryName)
{
    var _db = new products.Models.ProductContext();
    IQueryable<Product> query = _db.Products;
    if (categoryId.HasValue && categoryId > 0)
    {
        query = query.Where(p => p.CategoryID == categoryId);
    }
    if (!String.IsNullOrEmpty(categoryName))
    {
        query = query.Where(p =>
                            String.Compare(p.Category.CategoryName,
                            categoryName) == 0);
    }
    return query;
}

我有两个疑问:

  1. 如何修改此查询以只选择Active = 1的产品

  2. 当前查询以特定顺序返回行,我认为基于productId - 1,2,3,4,5等。如何对结果进行洗牌,使结果不按特定顺序返回?它可以是5、2、4、1、3,或者下一次运行时是3、5、1、4、2等等。

查询时Shuffle产品列表

首先是洗牌部分。这在IQueryable中是做不到的,所以最好在一些常见的地方引入一个通用的扩展方法:

public static void Swap<T>(ref T x, ref T y)
{
    var temp = x;
    x = y;
    y = temp;
}
public static T[] RandomShuffle<T>(this IEnumerable<T> source)
{
    var result = source.ToArray();
    if (result.Length < 2) return result;
    var random = new Random();
    for (int i = result.Length - 1; i > 0; i--)
    {
        int pos = random.Next(i + 1);
        if (pos != i) Swap(ref result[pos], ref result[i]);
    }
    return result;
} 

现在你的函数:

public IQueryable<Product> GetProducts(
                     [QueryString("id")] int? categoryId,
                     [RouteData] string categoryName)
{
    var _db = new products.Models.ProductContext();
    IQueryable<Product> query = _db.Products;
    query = query.Where(p => p.Active == 1); // the first question
    if (categoryId.HasValue && categoryId > 0)
    {
        query = query.Where(p => p.CategoryID == categoryId);
    }
    if (!String.IsNullOrEmpty(categoryName))
    {
        query = query.Where(p =>
                            String.Compare(p.Category.CategoryName,
                            categoryName) == 0);
    }
    return query;
}

你可以保持这种方式(在我看来更好),当你需要这种行为时,在调用端应用shuffle,比如GetProducts(....).RandomShuffle()。或者,如果你坚持在里面做,就把最后一行改成return query.RandomShuffle().AsQueryable();

要筛选Active产品,只需按以下方式扩展查询:

query = query.Where(p => p.CategoryID == categoryId && p.Active == 1);

要变换结果,您必须自己编写一些代码。它可能是这样的:

var shuffledList = new List<Product>();
var originalList = query.ToList();
var random = new Random();
while (originalList.Count() > 0) {
    var pick = random.Next(0, originalList.Count());
    var product = originalList[pick];
    shuffledList.Add(product);
    originalList.Remove(product);
}

shuffledList将以随机顺序包含您的产品。你会有一些内存负载,因为你有两倍的产品在你的内存。

我刚刚遇到的另一种可能是:

var random = new Random();    
query = query.OrderBy(product => random.Next());