Búsqueda en el árbol de expresiones utilizando contiene

c# contains expression-trees foreign-keys

Pregunta

EDITADO:

Estoy tratando de crear una consulta utilizando Árboles de Expresión para poder obtener un resultado simple, pero no he podido entenderlo.

Tengo algunas entidades de EF. Entity PointOfSale, que tiene algunos atributos como: Ubicación (que es un hijo de la Región) TypeOfClient ImportanceOfPOS QuantityOfSales.

Luego tengo un Filtro de clase, que tiene una lista de Regiones, una lista de TypesOfClients, un Dist of ImportanceOfPOS, y un valor mínimo y máximo para la cantidad de ventas.

Las clases se definen a continuación:

Entidades contexto = nuevas Entidades ();

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

Tenga en cuenta que todos los campos son opcionales: puedo o no tener regiones, puedo o no tener TypeOfClient. Además, en ValueForQuantities, puedo tener solo uno de los campos elegidos (máximo o mínimo).

Estoy tratando de construir una versión dinámica de esto:

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;

Que generará un código como este:

(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

Mi árbol de expresión hasta ahora es este:

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

Entonces, 2 preguntas:

1 - ¿Cómo puedo construir la parte de la región sin el método que devuelve todas las ubicaciones? 2 - ¿Cómo puedo crear la rama del árbol de expresiones para la parte Cantidad?

Muchísimas gracias y espero que ahora esté claro :)

Respuesta popular

Primero, construye una expresión Lambda de tu expresión "sub". Luego cree la llamada "Contiene" (en realidad es una llamada a Queryable.Any):

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

Estás construyendo esta expresión:

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

Edición: Parece que no necesitas construir un árbol de expresiones en absoluto. ¿Qué pasa con esto?

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

Espero que funcione.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow