0

I have written a Lambda expression that perfectly works on a single entity (Customer):

var property = typeof(Customer).GetProperty(inputArray[0], BindingFlags.Instance | BindingFlags.Public);
var parameter = Expression.Parameter(typeof(Customer));
var memberExpression = Expression.Property(parameter, property);
var eq = Expression.Equal(memberExpression, Expression.Constant(value));
//Combining eq with ANDs and ORs
var lambdaExpression = Expression.Lambda<Func<Customer, bool>>(eq, parameter);
var filteredCustomers = db.Customer.Where(lambdaExpression);

But I have more entities and I need to write a combined query that filters those entities as well. For example I have a Product entity and I want to filter products and customers at the same time. How can I change the above code so that it can work with multiple entities? Thanks in advance.

3
  • Do you want to filter Customer and Product at the same time or are you looking for a method that can filter both entities separately? Commented May 9, 2017 at 8:03
  • what "filter products and customers at the same time" means? Like multi thread "at the same time" or join "at the same time" :) Commented May 9, 2017 at 8:41
  • @ArkadiuszRaszeja join at the same time. Commented May 9, 2017 at 8:57

1 Answer 1

1

Basically principal is the same as I've posted in here. The difference is that we will have to retrieve values of the nested properties. So we no longer need PropertyValue in the input dictionary, instead we would want to know what is the Path of that property. For example: CustomerProducts.Customer.UserID

Then we can split that path into the array of names of properties in each nesting level and build MemberExpression that's pointing from the root object (which is CustomerProducts in this case) to the deepest property by which we want to filter the collection. Here's the working example:

        // instead of passing pairs of PropertyName - PropertyValue
        // we'll pass pairs of PropertyPath - PropertyValue
        var filters = new Dictiontionary<string, object>();
        IEnumerable<CustomerProduct > query = listOfCustomerProducts;

        // we will loop through the filters
        foreach (var filter in filters)
        {
            // split property path by dot character
            var propertyNames = filter.Key.Split('.');

            PropertyInfo property = null;
            var parameter = Expression.Parameter(typeof(CustomerProduct));

            MemberExpression memberExpression = null;

            // loop through all property names in path
            foreach (var t in propertyNames)
            {
                // get correct property type
                var type = property == null ? typeof(CustomerProduct) : property.PropertyType;
                // find property in the given type
                property = type.GetProperty(t, BindingFlags.Instance | BindingFlags.Public);
                if (property == null) break;

                // create member expression.
                memberExpression = memberExpression == null
                    // if there isn't one, create new, using parameter expression
                    ? Expression.Property(parameter, property)
                    // if there already is one, use it to get into the nested property
                    : Expression.Property(memberExpression, property);
            }

            if (property == null) continue;

            // Convert object type to the actual type of the property
            var value = Convert.ChangeType(filter.Value, property.PropertyType, CultureInfo.InvariantCulture);

            // Construct equal expression that compares MemberExpression for the property with converted value
            var eq = Expression.Equal(memberExpression, Expression.Constant(value));

            // Build lambda expresssion (x => x.SampleProperty == some-value)
            var lambdaExpression = Expression.Lambda<Func<CustomerProduct, bool>>(eq, parameter);

            // And finally use the expression to filter the collection
            query = query.Where(lambdaExpression.Compile());
        }
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for your answer. But what I was trying to say is to combine these two lambda expressions. For example a user can search like this : (Select UserID = 5 and ProductName = "Banana") or (Select UserID = 5 and ProductName = "Banana" or UserName="Jason")
So I assume that UserID is a property of Customer. And that Customer entity refers to Product entity in one to many relation, meaning Customer has a property ICollection<Product> or something like that. And Product entity has a ProductName property. Is that correct?
Actually there is no relation with tables. But Customer has UserID and Product has ProductName (there are a lot more properties in these entities). As I said there is no relation between these tables but I need to do searches as I said in the above comment.
So how do you want to join these tables if there's no relation between them?
I also have CustomerProduct table. So I join them using it. Sorry I forgot to mention that.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.