Поиск по дереву выражений с использованием содержит - PullRequest
1 голос
/ 07 февраля 2012

РЕДАКТИРОВАНИЕ:

Я пытаюсь создать запрос, используя деревья выражений, чтобы я мог получить простой результат, но я не смог его выяснить.

IУ меня есть некоторые объекты от EF.Entity PointOfSale, который имеет некоторые атрибуты, такие как: Location (который является дочерним для Region) TypeOfClient ImportanceOfPOS QuantityOfSales.

Затем у меня есть класс Filter, у которого есть список Regions, список TypesOfClients, Dist ofImportanceOfPOS, а также минимальное и максимальное значение количества продаж.

Классы определены ниже:

Контекст сущностей = новые сущности ();

class PointOfSale 
{
    int p_id;
    Location l;
    QuantityOfSales q;
    TypeOfCliente t;
    ImportanceOfClient i;
    int l_id_fk;
    int t_id_fk;
    int i_id_fk;
}

class Location
{
    int id;
    int region_id_fk;
}

class Region
{
     int id;
     string value;
}

class ValuesForQuantity
{
    int p_id; // ---> Equal to the POS_id
    int? min_value;
    int? max_value;
}

class QuantityOfSales
{
     int id;
     int value;
}

class TypeOfCliente
{
    int id;
    string value;
}

class ImportanceOfClient;
{
    int id;
    string value;
}


class Filter
{
     List<Region> rs;
     ValuesForQuantity v;
     List<ImportanceOfClient> is;
     List<TypeOfClient> ts;
}

Сохранитьпомните, что все поля являются необязательными: у меня могут быть или не быть регионы, у меня может быть или не быть TypeOfClient.Кроме того, в ValueForQuantities у меня может быть выбрано только одно из полей (только максимальное или минимальное).

Я пытаюсь создать динамическую версию этого:

var query = 
    from p in context.PointsOfSale
    where p.i exists in filter.is  &&
          p.t exists in filter.ts  &&
          p.l in (from l1 in context.Locations where l1 in filter.rs select r) &&
          p.t in (from q in context.Quantities where q.value < filter.v.max_value && q.value > filter.v.max_value)
    select p;

, которое будетсгенерируйте код, подобный следующему:

(p.i.id == filter.i[0] OR p.i.id == filter.i[1] OR p.i.id == filter.i[2])
AND
(p.t.id == filter.t[0] OR p.t.id == filter.t[1])
AND
p.l in (select id from Region r where (r.id == filter.r[0] OR r.id == filter.r[1])
AND
p.q.value < filter.v.max
AND
p.q.value > filter.v.min

Мое дерево выражений до сих пор выглядит так:

IQueryable<Points_of_sale> queryableDataPOS = context.Points_of_sale.AsQueryable<Points_of_sale>();
ParameterExpression pePOS = Expression.Parameter(typeof(Points_of_sale), "point_of_sale");
ParameterExpression peLocation = Expression.Parameter(typeof(Location), "location");
        List<Expression> expressions = new List<Expression>();

if (showRegion)
        {
            List<Location> ls = getAllLocations(regionList);
            List<Expression> choiceExpressions = new List<Expression>();
            foreach (Location l in ls)
            {
                Expression left = Expression.Property(pePOS, typeof(Points_of_sale).GetProperty("location_id_fk"));
                left = Expression.Convert(left, t.location_id.GetType());
                Expression right = Expression.Constant(t.territory_id);

                Expression expression = Expression.Equal(left, right);
                choiceExpressions.Add(expression);
            }
            if (choiceExpressions.Count > 0)
            {
                Expression totalChoiceExpression = choiceExpressions[0];
                for (int i = 1; i < choiceExpressions.Count; i++)
                {
                    totalChoiceExpression = Expression.Or(totalChoiceExpression, choiceExpressions[i]);
                }
                expressions.Add(totalChoiceExpression);
            }
        }

if (showTypeOfClient)
        {
            List<Expression> choiceExpressions = new List<Expression>();
            foreach (TypeOfClient choice in clients)
            {
                Expression left = Expression.Property(pePOS, typeof(Points_of_sale).GetProperty("type_of_client_id_fk"));
                left = Expression.Convert(left, choice.type_of_client.GetType());
                Expression right = Expression.Constant(choice.type_of_client_id);
                Expression expression = Expression.Equal(left, right);
                choiceExpressions.Add(expression);
            }
            if (choiceExpressions.Count > 0)
            {
                Expression totalChoiceExpression = choiceExpressions[0];
                for (int i = 1; i < choiceExpressions.Count; i++)
                {
                    totalChoiceExpression = Expression.Or(totalChoiceExpression, choiceExpressions[i]);
                }
                expressions.Add(totalChoiceExpression);
            }
        }

if (showImportanceOfClient)
        {
            List<Expression> choiceExpressions = new List<Expression>();
            foreach (ImportanceOfClient choice in importanceOfClients)
            {
                Expression left = Expression.Property(pePOS, typeof(Points_of_sale).GetProperty("importance_of_client_id_fk"));
                left = Expression.Convert(left, choice.importance_of_client_id.GetType());
                Expression right = Expression.Constant(choice.importance_of_client_id);
                Expression expression = Expression.Equal(left, right);
                choiceExpressions.Add(expression);
            }
            if (choiceExpressions.Count > 0)
            {
                Expression totalChoiceExpression = choiceExpressions[0];
                for (int i = 1; i < choiceExpressions.Count; i++)
                {
                    totalChoiceExpression = Expression.Or(totalChoiceExpression, choiceExpressions[i]);
                }
                expressions.Add(totalChoiceExpression);
            }
        }

if (showQuantityOfSales)
{
    // I have no idea how to build this one
}

Expression totalQuery = expressions[0];

// Make the && between all expressions
for (int i = 1; i < expressions.Count; i++)
{
    totalQuery = Expression.And(totalQuery, expressions[i]);
}

MethodCallExpression whereCallExpression = Expression.Call(
            typeof(Queryable),
            "Where",
            new Type[] { queryableDataPOS.ElementType },
            queryableDataPOS.Expression,
            Expression.Lambda<Func<Points_of_sale, bool>>(totalQuery, new ParameterExpression[] { pePOS }));

IQueryable<Points_of_sale> results = queryableDataPOS.Provider.CreateQuery<Points_of_sale>(whereCallExpression);

Итак, 2 вопроса:

1 - Как мне построитьчасть региона без метода, который возвращает все местоположения.2 - Как я могу создать ветвь дерева выражений для количества?

1 Ответ

1 голос
/ 07 февраля 2012

Сначала создайте выражение LambdaExpression из вашего выражения "sub". Затем создайте вызов «Contains» (на самом деле это вызов Queryable.Any):

var anyExpression = Expression.Call("Queryable.Any", sequence, lambda);

Вы строите это выражение:

Queryable.Any(sequence, x => x > 5);

Редактировать: похоже, вам вообще не нужно строить дерево выражений. Как насчет этого:

var query = context.P_List;

if(filter.zs != null && filter.zs.Count != 0)
 query = query.Where(p => filter.zs.Contains<int>(p.z));

if(filter.ys != null && filter.ys.Count != 0)
 query = query.Where(p => filter.ys.Contains<int>(p.y));

if(filter.as != null && filter.as.Count != 0)
 query = query.Where(p => (from ac in context.a_child where filter.as.Contains(ac) select a).Contains(p.a_child));

//and the same for v2...

var list = query.ToList(); //execute the SQL

Я надеюсь, что это работает.

...