Build Lambda Expression complex

6

I'm trying to build a Lambda Expression which is a little complex and I'm having difficulties.

The goal is this expression:

items = items.Where(x => sValues.Any(y => x.Contract_Rates.Select(z => z.CostCenterId).Contains(y)));

However, in RunTime , I do not know the name of the list that in the example is Contract_Rates , the issue is that I need to scan the collections of an object, I already have a method that fills the variable Collections in the code below) and check if this is a collection that implements IHasCostCenter , if positive, make Lambda Expression quoted.

What I have so far is:

var sValues = User.CostCenters.Select(x => x.CostCenterId).ToList();

ParameterExpression Parameter = Expression.Parameter(typeof(Contrato), "x");

foreach (var item in Collections.Select(x => x).Where(x => x.GetInterfaces().Any(y => y == typeof(IHasCostCenter))))
{
    // Obtenho o nome da lista (i.e. 'Contract_Rates')
    var PropertyName = typeof(T).GetProperties().FirstOrDefault(x => x.Name.Contains(item.Name)).Name;

    Expression Property = Expression.Property(Parameter, typeof(T).GetProperty(PropertyName));
    LambdaExpression Column = Expression.Lambda(Property, Parameter);
    Expression Select = Expression.Call(
        typeof(Queryable),
        "Select",
        new Type[] { items.ElementType, Column.Body.Type },
        items.Expression,
        Column);

    Expression Contains = Expression.Call(
        typeof(Enumerable),
        "Contains",
        new[] { sValuesType },
        Expression.Constant(sValues, sValues.GetType()),
        Select);

    MethodCallExpression Where = Expression.Call(
        typeof(Queryable),
        "Where",
        new Type[] { items.ElementType },
        items.Expression,
        Expression.Lambda(Contains, Parameter));

    items = items.Provider.CreateQuery<T>(Where);

But I can not properly develop how I get the SELECT of the expression x.Contract_Rates.Select(y => y.CostCenterId) and how do I get the ANY of the expression sValues.Any(y => x.Contrato_Rateios.Select(z => z.CentroCustoId).Contains(y))

Any help will be appreciated.

    
asked by anonymous 09.12.2014 / 14:11

1 answer

0

The query you are trying to construct, (perhaps) is not (is) necessary. You can achieve the same result by using join between collections items and sValues .

See an example below:

var result = from x in items
             join y in sValues on x.Contract_Rates.Select(z => z.CostCenterId).Contains(y)
             select x;

Edit 1

After your comment, I understood your problem better. It may be easier to resolve your problem with OOP (if you have access to the Items collection class). The alternative would be:

In classes that should make this behavior available, you implement an interface requiring a method (which you will always know the name of) to get to the IHasCostCenter collection:

public interface IHasCostCenterAvailable {

   IHasCostCenter GetIHasCostCenterCollection();

   // outra opção
   //IHasCostCenter IHasCostCenterCollection {get;set;}
}

public class CollectionItems: IHasCostCenterAvailable {

   IHasCostCenter GetIHasCostCenterCollection()
   {
      return this.Contract_Rates;
   }
}


public class OutraCollectionItems: IHasCostCenterAvailable {

   IHasCostCenter GetIHasCostCenterCollection()
   {
      return this.OutroNomeQualquerDeColecao;
   }
}


// Exemplo de preenchimento
var items = new List<IHasCostCenterAvailable>();
items.Add(new CollectionItems());
items.Add(new OutraCollectionItems());

// Nova consulta.
var result = from x in items
             join y in sValues on x.GetIHasCostCenterCollection().Select(z => z.CostCenterId).Contains(y)
             select x;

In this second suggestion, you do not care about the names of the collections, because you will always access the desired collection through the IHasCostCenterAvailable interface. So, your problem, knowing the name of the collection, is over.

Edit 2 If you do not have access to the items collection class directly, there are a few other ways to access it, which could be via:

  • default Visitor;
  • methods extensions;
  • reflection.
09.12.2014 / 14:55