表达式树搜索使用包含

时间:2012-02-07 19:17:31

标签: c# foreign-keys expression-trees contains

编辑:

我正在尝试使用表达式树创建一个查询,以便我可以获得一个简单的结果,但我无法弄清楚它。

我有一些来自EF的实体。 实体PointOfSale,它具有以下属性: 位置(这是地区的孩子) TypeOfClient ImportanceOfPOS QuantityOfSales。

然后我有一个类Filter,它有一个Regions列表,一个TypesOfClients列表,一个Distance of ImportanceOfPOS,以及一个销售数量的最小值和最大值。

课程定义如下:

实体上下文=新实体();

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 - 如何为Quantity部分创建表达式树分支?

Tnks很多,我希望现在很清楚:)

1 个答案:

答案 0 :(得分:1)

首先,从表达式“sub”构建LambdaExpression。然后构建“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

我希望有效。