-->

Dynamic Linq Search Expression on Navigation Prope

2019-08-09 05:31发布

问题:

We are building dynamic search expressions using the Dynamic Linq library. We have run into an issue with how to construct a lamba expression using the dynamic linq library for navigation properties that have a one to many relationship.

We have the following that we are using with a contains statement-

 Person.Names.Select(FamilyName).FirstOrDefault()

It works but there are two problems.

  1. It of course only selects the FirstOrDefault() name. We want it to use all the names for each person.

  2. If there are no names for a person the Select throws an exception.

It is not that difficult with a regular query because we can do two from statements, but the lambda expression is more challenging.

Any recommendations would be appreciated.

EDIT- Additional code information...a non dynamic linq expression would look something like this.

 var results = persons.Where(p => p.Names.Select(n => n.FamilyName).FirstOrDefault().Contains("Smith")).ToList();

and the class looks like the following-

public class Person
{
 public bool IsActive { get; set;}

 public virtual ICollection<Name> Names {get; set;}
}

public class Name
{
public string GivenName { get; set; }

public string FamilyName { get; set; }

public virtual Person Person { get; set;}
}

回答1:

We hashed it out and made it, but it was quite challenging. Below are the various methods on how we progressed to the final result. Now we just have to rethink how our SearchExpression class is built...but that is another story.

1. Equivalent Query Syntax

var results = from person in persons
from name in person.names
where name.FamilyName.Contains("Smith")
select person;

2. Equivalent Lambda Syntax

var results = persons.SelectMany(person => person.Names)
                     .Where(name => name.FamilyName.Contains("Smith"))
                     .Select(personName => personName.Person);

3. Equivalent Lambda Syntax with Dynamic Linq

var results = persons.AsQueryable().SelectMany("Names")
                     .Where("FamilyName.Contains(@0)", "Smith")
                     .Select("Person");

Notes - You will have to add a Contains method to the Dynamic Linq library.

EDIT - Alternatively use just a select...much more simple...but it require the Contains method addition as noted above.

var results = persons.AsQueryable().Where("Names.Select(FamilyName)
                                   .Contains(@0", "Smith)

We originally tried this, but ran into the dreaded 'No applicable aggregate method Contains exists.' error. I a round about way we resolved the problem when trying to get the SelectMany working...therefore just went back to the Select method.