如何参数化 Entity Framework 中的查询?
How to parametrize a query in Entity Framework?
我是英孚新手。我有一个包含项目列表的 table。我在我的软件中发现了一个可以找到所有项目的查询。
public Project[] FindAll()
{
var projects = new List<Project>();
using (var db = new ProjetDbConext())
{
var qProjects = from project in db.ProjectSet
where project.CreateDateTime != null
select project;
projects = qProjects.ToList();
}
return projects.ToArray();
}
这看起来不错,但我不确定如何对其进行参数化。我需要这个,因为我正在实现一个搜索功能,试图重新使用来自 EF 的一些查询逻辑。
这需要一个元组列表。每个元组基本上都有一个属性和一个搜索词列表。
例如。元组(名字,{Prasaanth,比尔};元组(姓氏,{尼拉坎丹,盖茨};
这意味着我需要编写一个 select 查询来搜索 FirstName 是 Prasaanth 或 Bill 的项目。如果列表只有一项。
例如。 Tuple( Company , { Microsoft} ; 然后我只需要在查询中搜索一个 where 条件。
public Project[] LoadSearchProjects(List<System.Tuple<string, List<string>>> searchTerms)
{
var projects = new List<Project>();
using (var db = new ProjetDbConext())
{
foreach (System.Tuple<string, List<string>> pair in searchTerms)
{
string attribute = pair.Item1;
List<string> terms = pair.Item2;
/// logic here
}
}
return projects.ToArray();
}
我总是可以写一个 if 条件:
if(attribute.equals("FirstName"){
// query project.FirstName in the where conditon
}
但是我要搜索的属性太多了。
我知道ADO.NET这样做的方法:
mycommands = new SqlCommand(" select projects from from Persons where '"+attibute+"' = some search terms ...
我不知道如何在我的 EF 查询中执行类似的操作。
1) EF 是否允许我对动态属性进行搜索?或使用 '"+attribute+"' 进行参数化 ??
2) 是否有更好的数据结构可以用来简化我的结构而不是使用 List<Tuple<string, List<string>>
?
3) 有人建议我使用第 3 方 LINQKit 或动态 linq,但我不确定如何将其集成到 EF 查询中。
如果其中大部分听起来像大学生代码,我深表歉意。如果需要任何其他详细信息,请告诉我。
此致,
普拉桑
更新:
按照安德烈的回答工作方法。我的问题是,如果我的数据库中的任何特定条目显示 Name 为 Null,这将不起作用。
private static Expression<Func<TEntity, bool>> BuildStringFilter<TEntity, TProp>(
Tuple<string, List<string>> filter)
{
// entity is the Project table
var entity = Expression.Parameter(typeof (TEntity));
var prop = Expression.Property(entity, filter.Item1);
//check if contains returns true
var body = filter.Item2
.Select(v => Expression.Equal(Expression.Call(prop,
typeof (String).GetMethod("Contains"),
new Expression[] { Expression.Constant(v) }), Expression.Constant(true)))
.Aggregate(Expression.Or);
var result = (Expression<Func<TEntity, bool>>) Expression.Lambda(body, entity);
return result;
}
我可以通过任何方式修改表达式,以便 Contains 方法:
道具,
typeof (String).GetMethod("Contains"),
新表达式[] { Expression.Constant(v)
如果属性 (prop) 的值为 null 是否有效?
我在这里吐槽,但我认为这样的事情会更简单:
public Project[] Find(Expression<Func<Project, bool> filter = null)
{
using (var db = new ProjetDbConext())
{
var query = db.ProjectSet.Where(p => p.CreateDateTime != null);
if(filter != null)
query = query.Where(filter);
return query.ToArray();
}
}
像这样使用它:
var projects = repo.Find(p => p.id > 100);
您可以使用代码段构建过滤器表达式:
public static Expression<Func<TEntity, bool>> BuildFilter<TEntity, TProp>(
KeyValuePair<string, IEnumerable<TProp>> filter)
{
var entity = Expression.Parameter(typeof(TEntity));
var prop = Expression.Property(entity, filter.Key);
var body = filter.Value
.Select(v => Expression.Equal(prop, Expression.Constant(v)))
.Aggregate((curr, next) => Expression.Or(curr, next));
var result = (Expression<Func<TEntity, bool>>)Expression.Lambda(body, entity);
return result;
}
并这样称呼它:
var filter = new KeyValuePair<string, IEnumerable<string>> (
"FirstName",
new [] {"Alice", "Bob"}
);
var predicate = BuildFilter<Item, string>(filter);
var result = ctx.Items.Where(predicate);
我是英孚新手。我有一个包含项目列表的 table。我在我的软件中发现了一个可以找到所有项目的查询。
public Project[] FindAll()
{
var projects = new List<Project>();
using (var db = new ProjetDbConext())
{
var qProjects = from project in db.ProjectSet
where project.CreateDateTime != null
select project;
projects = qProjects.ToList();
}
return projects.ToArray();
}
这看起来不错,但我不确定如何对其进行参数化。我需要这个,因为我正在实现一个搜索功能,试图重新使用来自 EF 的一些查询逻辑。
这需要一个元组列表。每个元组基本上都有一个属性和一个搜索词列表。
例如。元组(名字,{Prasaanth,比尔};元组(姓氏,{尼拉坎丹,盖茨};
这意味着我需要编写一个 select 查询来搜索 FirstName 是 Prasaanth 或 Bill 的项目。如果列表只有一项。
例如。 Tuple( Company , { Microsoft} ; 然后我只需要在查询中搜索一个 where 条件。
public Project[] LoadSearchProjects(List<System.Tuple<string, List<string>>> searchTerms)
{
var projects = new List<Project>();
using (var db = new ProjetDbConext())
{
foreach (System.Tuple<string, List<string>> pair in searchTerms)
{
string attribute = pair.Item1;
List<string> terms = pair.Item2;
/// logic here
}
}
return projects.ToArray();
}
我总是可以写一个 if 条件:
if(attribute.equals("FirstName"){
// query project.FirstName in the where conditon
}
但是我要搜索的属性太多了。
我知道ADO.NET这样做的方法:
mycommands = new SqlCommand(" select projects from from Persons where '"+attibute+"' = some search terms ...
我不知道如何在我的 EF 查询中执行类似的操作。
1) EF 是否允许我对动态属性进行搜索?或使用 '"+attribute+"' 进行参数化 ??
2) 是否有更好的数据结构可以用来简化我的结构而不是使用 List<Tuple<string, List<string>>
?
3) 有人建议我使用第 3 方 LINQKit 或动态 linq,但我不确定如何将其集成到 EF 查询中。
如果其中大部分听起来像大学生代码,我深表歉意。如果需要任何其他详细信息,请告诉我。
此致, 普拉桑
更新: 按照安德烈的回答工作方法。我的问题是,如果我的数据库中的任何特定条目显示 Name 为 Null,这将不起作用。
private static Expression<Func<TEntity, bool>> BuildStringFilter<TEntity, TProp>(
Tuple<string, List<string>> filter)
{
// entity is the Project table
var entity = Expression.Parameter(typeof (TEntity));
var prop = Expression.Property(entity, filter.Item1);
//check if contains returns true
var body = filter.Item2
.Select(v => Expression.Equal(Expression.Call(prop,
typeof (String).GetMethod("Contains"),
new Expression[] { Expression.Constant(v) }), Expression.Constant(true)))
.Aggregate(Expression.Or);
var result = (Expression<Func<TEntity, bool>>) Expression.Lambda(body, entity);
return result;
}
我可以通过任何方式修改表达式,以便 Contains 方法:
道具, typeof (String).GetMethod("Contains"), 新表达式[] { Expression.Constant(v)
如果属性 (prop) 的值为 null 是否有效?
我在这里吐槽,但我认为这样的事情会更简单:
public Project[] Find(Expression<Func<Project, bool> filter = null)
{
using (var db = new ProjetDbConext())
{
var query = db.ProjectSet.Where(p => p.CreateDateTime != null);
if(filter != null)
query = query.Where(filter);
return query.ToArray();
}
}
像这样使用它:
var projects = repo.Find(p => p.id > 100);
您可以使用代码段构建过滤器表达式:
public static Expression<Func<TEntity, bool>> BuildFilter<TEntity, TProp>(
KeyValuePair<string, IEnumerable<TProp>> filter)
{
var entity = Expression.Parameter(typeof(TEntity));
var prop = Expression.Property(entity, filter.Key);
var body = filter.Value
.Select(v => Expression.Equal(prop, Expression.Constant(v)))
.Aggregate((curr, next) => Expression.Or(curr, next));
var result = (Expression<Func<TEntity, bool>>)Expression.Lambda(body, entity);
return result;
}
并这样称呼它:
var filter = new KeyValuePair<string, IEnumerable<string>> (
"FirstName",
new [] {"Alice", "Bob"}
);
var predicate = BuildFilter<Item, string>(filter);
var result = ctx.Items.Where(predicate);