Previously, I had great help on my previous question, thank you vyrp , How do I create and populate a dynamic object using a dynamically built lambda expression
I'm now looking to search the dynamic object, and as before, I don't know the objects properties, and therefore what I'm searching until runtime.
Here's the code that builds the dynamic object:
// Get list of optional fields
var optFieldList = await _tbList_FieldRepository.GetAsync(lf => lf.ListID == listId && lf.DisplayInList == true);
// order list of optional fields
optFieldList.OrderBy(lf => lf.DisplayOrder);
// Get base Data excluding Inactive if applicable
IEnumerable<tbList_Data> primaryData = await _tbList_DataRepository.GetAsync(ld => ld.ListID == listId && (ld.IsActive == includeInactive ? ld.IsActive : true));
// Build IEnumerable<dynamic> from base results plus any optional fields to be displayed in table
var results = primaryData.Select(pd => {
dynamic result = new System.Dynamic.ExpandoObject();
result.Id = pd.ID;
result.PrimaryData = pd.PrimaryData;
result.DisplayOrder = pd.DisplayOrder;
result.IsActive = pd.IsActive;
foreach (var optField in optFieldList)
{
switch (optField.FieldType.ToLower()) {
case "text":
((IDictionary<string, object>)result).Add(optField.FieldName, pd.tbList_DataText.Where(ld => ld.DataRowID == pd.ID && ld.ListColumnID == optField.ID).Select(ld => ld.DataField).DefaultIfEmpty("").First());
break;
}
}
return result;
});
For the purpose of testing, I have 2 dynamic fields, "PhoneNumber" and "FuelType"
I can search the known field(s) i.e. PrimaryData, no problem, as below.
results = results.Where(r => r.PrimaryData.Contains(searchString));
And the following will work if I know the field PhoneNumber at design time
results = results.Where(r => r.PhoneNumber.Contains(searchString));
but what I want to do, is something like:
results = results.Where(r => r.PrimaryData.Contains(searchString)
|| foreach(var optField in optFieldList)
{
r.optField.FieldName.Contains(searchString)
})
ending up with
results = results.Where(r =>
r.PrimaryData.Contains(searchString)
|| r.PhoneNumber.Contains(searchString) ||
r.FuelType.Contains(searchString));
but obviously that code doesn't work. I've tried a bunch of different attempts, none successful, so I'm looking for suggestions. Thanks
Since you know that the dynamic
element of your query is actually ExpandoObject
, hence IDictionary<string, object>>
, you can safely cast it to dictionary interface and use it to access the property values by name, while Enumerable.Any method can be used to simulate dynamic ||
condition:
results = results.Where(r => r.PrimaryData.Contains(searchString)
|| optFieldList.Any(f =>
{
object value;
return ((IDictionary<string, object>)r).TryGetValue(f.FieldName, out value)
&& value is string && ((string)value).Contains(searchString);
}));