I have been digging this quite a while.
public class Person
{
public string Name { get; set; }
public string Age { get; set; }
public List<Person> Children { get; set; }
}
I want a single LINQ query to find out "All the persons whose Age > 4
in this collection".
Note: You have to traverse Collection of Person
+ Collection of Children
, so each children object will have a collection of Person
till Children
becomes null
.
Create a visitor. In this example by implementing a helper class:
public static class Helpers
public static IEnumerable<Person> GetDescendants(this Person person)
{
foreach (var child in person.Children)
{
yield return child;
foreach (var descendant in child.GetDescendants())
{
yield return descendant;
}
}
}
this is one of the times where the "yield return many" would be useful.
First i can't understand why all your properties private
and Age
is not int
type. So my class looks like this:
public partial class Person
{
public string Name { get; set; }
public int Age { get; set; }
public List<Person> Childrens { get; set; }
}
Note partial
word. This word will allow you to place your class logic in separate files and this could be usefull when you creating some custom logic in class.
Then I simply create this method in different file:
public partial class Person
{
public Person GetPersonWithChindren(int maxAge)
{
return new Person
{
Age = this.Age,
Name = this.Name,
Childrens = this.Childrens != null
? this.Childrens
.Where(x => x.Age < maxAge)
.Select(x => x.GetPersonWithChindren(maxAge)) //this line do recursive magic
.ToList()
: null
};
}
}
As you can see this method checking Age
of each child and if Age
is ok then it checks next level of hierarchy untill Childrens
is null
.
So you can use it like this:
var person = new Person()
{
//initialisation of your collection here
}
//result will contains only nodes where Person have age < 4 and Childs that have age < 4
var result = person.GetPersonWithChindren(4);
Note that this solution will work normal with linqToEntities. But if you using LinqToSQL this expression produces query to DB on each Person
entity. So if you have many Persons and deep hierarhy it will costs you a lot of machine time. In that case you should to write stored procedure with CTE instead of LinQ query.
UPDATE:
You even can write more general solution with a help of Func<T>
class like this:
public partial class Person
{
public Person GetPersonWithChindren(Func<Person, bool> func)
{
return new Person
{
Age = this.Age,
Name = this.Name,
Childrens = this.Childrens != null
? this.Childrens
.Where(x => func(x))
.Select(x => x.GetPersonWithChindren(func))
.ToList()
: null
};
}
}
And then you can use it like this:
var result = person.GetPersonWithChindren(x => x.Age < 4);
You always can change your criteria now where you want to use your function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With