I would like to do the following
public async Task<List<dynamic>> searchEntities(string query, list<string> columnNames)
{
var columNames = GetPropertiesUsingReflectionAndfilter<Entity>(columnNames);
await db.entities.select(x => { columnNames }).where(...)..ToListAsync();
}
I need to expose a custom EF Search Method in a Controller. I would like to offer a partial response. $search is not avail in version of OData I am using.
Is this possible with IQueryable perhaps?
Alternative would be to build Parameterized SQL query. Would like to know if there is a better way using EF and Linq? Thanks..
Solution:
Thanks to @IvanStoev, I ultimately added a library, System.Linq.Dynamic (free with > 1 million downloads) , to accomplish this. I now have.
using System.Linq.Dynamic;
var columnNames = GetColumNames<Entity>(qry.TableList);
var selector = "new(" + String.Join(", ", columnNames.ToArray()) + ")";
var results = await db.Lessons
.Where(x => x.LessonName.Contains(qry.Query) == true || x.HTML.Contains(qry.Query) == true)
.Select(selector)
.ToListAsync();
return Ok(results);
TLDR. Full usage for my scenario.
Controller:
[HttpPost, Route("Search/Lessons")]
public async Task<IHttpActionResult> SearchLessons([FromBody] SearchQuery qry)
{
var columnNames = GetColumNames<Lesson>(qry.TableList);
if (columnNames.Count < 1) {
return BadRequest();
}
var selector = "new(" + String.Join(", ", columnNames.ToArray()) + ")";
var results = await db.Lessons
.Where(x => x.LessonName.Contains(qry.Query) == true || x.HTML.Contains(qry.Query) == true)
.Select(selector)
.ToListAsync();
return Ok(results);
}
And Helpers:..
private List<string> GetColumNames<T>(List<string> columnsToFetch = null)
{
var properties = GetProperties<T>();
var columnNames = new List<string>();
if (columnsToFetch == null)
{
return properties;
}
foreach (var columnRequested in columnsToFetch)
{
var matchedColumn = properties
.Where(x => x.ToLower() == columnRequested.ToLower())
.FirstOrDefault();
if (matchedColumn != default(string))
{
columnNames.Add(matchedColumn);
}
}
return columnNames;
}
And..
private List<string> GetProperties<T>()
{
dynamic model = TypeDescriptor.GetProperties(Activator.CreateInstance<T>());
List<string> result = new List<string>();
foreach (var prop in model)
{
result.Add(prop.Name);
}
return result;
}
Disclaimer : I'm the owner of the project Eval-Expression.NET
This library is not FREE but allows you to compile & execute C# code at runtime. By example, you can perform any LINQ dynamically
Tutorial: LINQ Dynamic
Example:
public searchEntities(string query, list<string> columnNames)
{
await db.entities.SelectDynamic(x => "{" + string.Join(",", columnNames) + "}")
.where(...)..ToListAsync();
}
I don't see how that would be possible.
First of all, to return the list from searchEntities, the select would need to create a named object.
What you could do is pass in a function-expression to searchEntities
public Task<List<T>> searchEntities<T>(EXpression<Func<Entity, T> selector)
{
return await db.entities.select(selector).where(...)..ToListAsync();
}
Expression<Func<Entity, AdHocClass1> selector1 = (Entity e)=> new AdHocClass1 {...};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.