如何动态构建Select与Linq&实体框架

时间:2017-06-08 16:41:21

标签: c# entity-framework linq linq-to-entities iqueryable

我想做以下

public async Task<List<dynamic>> searchEntities(string query, list<string> columnNames)
{
   var columNames = GetPropertiesUsingReflectionAndfilter<Entity>(columnNames);
   await db.entities.select(x => { columnNames }).where(...)..ToListAsync();
}

我需要在Controller中公开自定义EF搜索方法。我想提供部分回应。 $ search在我正在使用的OData版本中无效。

这可能与IQueryable有关吗?

替代方案是构建参数化SQL查询。想知道是否有更好的方式使用EF和Linq?感谢..

解决方案:

感谢@IvanStoev,我最终添加了一个库,System.Linq.Dynamic (免费下载> 100万次),以实现这一目标。我现在有。

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。完全用于我的方案。

控制器:

[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);
}

和助手:..

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;
}

和..

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;
    }

2 个答案:

答案 0 :(得分:1)

免责声明:我是该项目的所有者Eval-Expression.NET

这个库不是免费的,但允许你编译&amp;在运行时执行C#代码。例如,您可以动态执行任何LINQ

教程:LINQ Dynamic

示例:

Server server = new Server();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    @Override
    public void run() {
        server.save();
    }
}));
server.listen();

答案 1 :(得分:0)

我看不出那是可能的。

首先,要从searchEntities返回列表,select需要创建一个命名对象。

您可以做的是将函数表达式传递给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 {...};