C# -MongoDB: список внутри оператора Where с оператором OR - PullRequest
1 голос
/ 26 апреля 2020

У меня есть список категорий, и я создаю динамический c запрос.

var Categories = GetCategories(); //list of string
query = query.Where(x => x.CategoryID == ?????);

Теперь, как мне сделать, чтобы в списке категорий был оператор ИЛИ для каждой категории внутри предложения where?

Как, например, предположим, что список категорий имеет две категории. Так что это будет похоже на

query = query.Where(x => x.CategoryID == Categories[0] | x.CategoryID == Categories[1]);

, но это должно быть динамически c.

Ответы [ 4 ]

1 голос
/ 26 апреля 2020

вы могли бы сделать это так

query.Where(x => Categories.Contains(x.CategoryID))
0 голосов
/ 26 апреля 2020

Я закончил этим, и это сработало.

var subChildCategories = GetChildCategories(Convert.ToInt32(getProductsDomainModel.CategoryID));
var parameter = Expression.Parameter(typeof(FullProductDomainModel));
BinaryExpression binaryExpression = null;

foreach (var category in subChildCategories)
{
    var prop = Expression.Property(parameter, "CategoryID");
    var value = Expression.Constant(category.ToString());
    var newBinary = Expression.MakeBinary(ExpressionType.Equal, prop, value);

    binaryExpression =
        binaryExpression == null
        ? newBinary
        : Expression.MakeBinary(ExpressionType.Or, binaryExpression, newBinary);
}

var cookedExpression = Expression.Lambda<Func<FullProductDomainModel, bool>>(binaryExpression, parameter).Compile();

query = query.Where(cookedExpression).AsQueryable();
0 голосов
/ 26 апреля 2020

Надеюсь, это решение поможет, если мой первоначальный ответ с предложением использовать деревья выражений будет бесполезным:

Код

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp39
{
    class Program
    {
        public struct CategoryEntry {
            public int Id { get; set; }
            public string Description { get; set; }
        }

        static void Main(string[] args)
        {
            var categories = new List<CategoryEntry>();
            categories.Add(new CategoryEntry() { Id = 1, Description = "1-First"});
            categories.Add(new CategoryEntry() { Id = 1, Description = "1-Second" });
            categories.Add(new CategoryEntry() { Id = 2, Description = "2-First" });
            categories.Add(new CategoryEntry() { Id = 3, Description = "3-First" });

            var categoryIDs = new HashSet<int>();
            categoryIDs.Add(1);
            categoryIDs.Add(2);

            Console.WriteLine("The sought Ids \n");
            foreach (var categoryId in categoryIDs) {
                Console.WriteLine(categoryId);
            }
            Console.WriteLine("\n");

            // returns a collection of collections, one collection per queried category id
            var result = categoryIDs.Select(id => categories.FindAll(c => c.Id == id));
            Console.WriteLine("The result from the variable result \n");
            foreach (var collection in result)
            {
                collection.ForEach(entry => Console.WriteLine(entry.Description));
            }

            Console.WriteLine("\n");
            // returns a single collection with all found categories for all queried categories ids 
            var flatResult = categoryIDs.SelectMany(id => categories.FindAll(c => c.Id == id));
            Console.WriteLine("The result from the variable flatResult \n");
            foreach (var entry in flatResult)
            {
                Console.WriteLine(entry.Description);
            }

            Console.ReadLine();
        }
    }
}

Вывод

Запрашиваемые идентификаторы

1 2

Результат из переменной result

1-First 1-Second 2-First

Результат от переменной flatResult

1-первый 1-второй 2-первый

0 голосов
/ 26 апреля 2020

Похоже, вам нужно использовать Деревья выражений (C#)

Деревья выражений представляют код в древовидной структуре данных, где каждый узел является выражением Например, вызов метода или двоичная операция, такая как x

. Вы можете компилировать и запускать код, представленный деревьями выражений. Это позволяет динамически c модифицировать исполняемый код, выполнять запросы LINQ в различных базах данных и создавать динамические c запросы. Для получения дополнительной информации о деревьях выражений в LINQ см. Как использовать выражение деревья для построения динамических c запросов (C#) .

Вот очень простой пример для начала:

В следующем примере кода демонстрируется Как скомпилировать дерево выражений и запустить полученный код.

    // Creating an expression tree.  
    Expression<Func<int, bool>> expr = num => num < 5;  

    // Compiling the expression tree into a delegate.  
    Func<int, bool> result = expr.Compile();  

    // Invoking the delegate and writing the result to the console.  
    Console.WriteLine(result(4));  

    // Prints True.  

    // You can also use simplified syntax  
    // to compile and run an expression tree.  
    // The following line can replace two previous statements.  
    Console.WriteLine(expr.Compile()(4));  

    // Also prints True.

Вот пример того, как использовать деревья выражений для построения динамических c запросов Как использовать деревья выражений для Построение динамических c запросов (C#) :

В следующем примере показано, как использовать деревья выражений для построения запроса к источнику данных IQueryable и последующего его выполнения. Код создает дерево выражений для представления следующего запроса:

   companies.Where(company => (company.ToLower() == "coho winery" ||
       company.Length > 16))
          .OrderBy(company => company)

Методы фабрики в пространстве имен System.Linq.Expressions используются для создания деревьев выражений, которые представляют выражения, составляющие общий запрос. Выражения, представляющие вызовы стандартных методов оператора запроса, ссылаются на реализации Queryable этих методов. Окончательное дерево выражений передается реализации CreateQuery (Expression) поставщика источника данных IQueryable для создания исполняемого запроса типа IQueryable. Результаты получены путем перечисления этой переменной запроса.

// Add a using directive for System.Linq.Expressions.  

string[] companies = { "Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light",  
                   "Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works",  
                   "Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders",  
                   "Blue Yonder Airlines", "Trey Research", "The Phone Company",  
                   "Wingtip Toys", "Lucerne Publishing", "Fourth Coffee" };  

// The IQueryable data to query.  
IQueryable<String> queryableData = companies.AsQueryable<string>();  

// Compose the expression tree that represents the parameter to the predicate.  
ParameterExpression pe = Expression.Parameter(typeof(string), "company");  

// ***** Where(company => (company.ToLower() == "coho winery" || company.Length > 16)) *****  
// Create an expression tree that represents the expression 'company.ToLower() == "coho winery"'.  
Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));  
Expression right = Expression.Constant("coho winery");  
Expression e1 = Expression.Equal(left, right);  

// Create an expression tree that represents the expression 'company.Length > 16'.  
left = Expression.Property(pe, typeof(string).GetProperty("Length"));  
right = Expression.Constant(16, typeof(int));  
Expression e2 = Expression.GreaterThan(left, right);  

// Combine the expression trees to create an expression tree that represents the  
// expression '(company.ToLower() == "coho winery" || company.Length > 16)'.  
Expression predicateBody = Expression.OrElse(e1, e2);  

// Create an expression tree that represents the expression  
// 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))'  
MethodCallExpression whereCallExpression = Expression.Call(  
    typeof(Queryable),  
    "Where",  
    new Type[] { queryableData.ElementType },  
    queryableData.Expression,  
    Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe }));  
// ***** End Where *****  

// ***** OrderBy(company => company) *****  
// Create an expression tree that represents the expression  
// 'whereCallExpression.OrderBy(company => company)'  
MethodCallExpression orderByCallExpression = Expression.Call(  
    typeof(Queryable),  
    "OrderBy",  
    new Type[] { queryableData.ElementType, queryableData.ElementType },  
    whereCallExpression,  
    Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));  
// ***** End OrderBy *****  

// Create an executable query from the expression tree.  
IQueryable<string> results = queryableData.Provider.CreateQuery<string>(orderByCallExpression);  

// Enumerate the results.  
foreach (string company in results)  
    Console.WriteLine(company);  

/*  This code produces the following output:  

    Blue Yonder Airlines  
    City Power & Light  
    Coho Winery  
    Consolidated Messenger  
    Graphic Design Institute  
    Humongous Insurance  
    Lucerne Publishing  
    Northwind Traders  
    The Phone Company  
    Wide World Importers  
*/
...