I need to order a collection of data dynamically. I have this working at the top level:
//where prop is a string passed in, ex: "ShoeSize"
_clowns
.AsEnumerable()
.OrderBy(x => x.GetType().GetProperty(prop)?.GetValue(x))
.Select(x => x.Id)
.ToList();
And that works so long as I only need to order by some property of Clowns
. But what if I need to order Clowns
by a property of their Car
? I think I'm close, but can't clear the gap:
//for prop = "Car.ClownCapcity"
var queryBuilder = _clowns;
var orderProp = prop;
if (prop.Contains(".")){
string[] props = prop.Split(".");
foreach(string oneProp in props){
if (props.Last() != oneProp){
//this line is wrong for sure
queryBuilder.Include(x => x.GetType().GetProperty(oneProp));
} else {
orderProp = oneProp;
}
}
}
queryBuilder.AsEnumerable()
.OrderBy(x => x.GetType().GetProperty(orderProp)?.GetValue(x))
.Select(x => x.Id)
.ToList();
This doesn't work because I cannot build up queryBuilder
, reassigning at the Include
doesn't work because the return type is different. I also haven't figured out how to dynamically go deeper inside the final OrderBy
.
Is there a decent way to do this in Linq, or should I go build a SQL string?
There are security concerns, those can be handled elsewhere and aren't terribly relevant to this question
Update
Progress! Got it to work two-levels deep, but only when I explicitly know it's two-levels deep. I haven't figured out the abstraction yet.
if (prop.Contains(".")){
string[] props = prop.Split(".");
string includeProp = props.FirstOrDefault();
string orderProp = props.LastOrDefault();
return _Clowns
.Include(includeProp)
.AsEnumerable()
.OrderBy(x => {
var y = x.GetType().GetProperty(formattedProp)?.GetValue(x);
return y?.GetType().GetProperty(orderProp)?.GetValue(y);
})
.Select(x => x.Id)
.ToList();
}