构建从 linq 到 ef 核心的动态 where 查询
Building dynamic where query from linq to ef core
我的模型如下所示
public class Country
{
public int Id {get; set;}
public string Name {get; set;}
}
public class User
{
public int Id{get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
public string Email {get; set;}
}
public class Company
{
public int Id{get; set;}
public string Name {get;set;}
public string City {get; set;}
public string Address1 {get; set;}
public string Address2 {get; set;}
[ForeignKey("Country")]
public int CountryId{get; set;}
public Country Country{get; set;}
public ICollection<CompanyUsers> CompanyUsers {get; set;}
}
public class CompanyUsers
{
public int Id{get; set;}
[ForeignKye("Company")]
public int CompanyId {get; set;}
[ForeignKye("User")]
public int UserId {get; set;}
public Country Country{get; set;}
public User User{get; set;}
}
我想让用户能够通过 Country, Company or User class
中定义的任何 属性 搜索公司记录,除了 Id 属性
我试着查看这个 SO discussion,但它不处理导航 属性。有人可以帮我构建动态 where 子句,包括导航属性 属性.
使用此实现我只能执行以下操作
myContext.CompanyEntity
.Where(FilterLinq<CompanyEntity>
.GetWherePredicate(searchParams))
.ToList();
public class SearchField
{
public string Key { get; set; }
public string Value { get; set; }
}
扩展您所指答案的想法并不那么复杂。
您需要更改假设,以便 SerchField 中的 属性 名称可以包含 属性 路径的定义,例如 Company.City
或 Company.Country.Name
以及 属性 FirstName
。而你需要处理它:
所以不要像这样简单地 属性:
Expression columnNameProperty = Expression.Property(pe, fieldItem.Name);
您需要处理 属性 链:
Expression columnNameProperty = GetPropertyExpression(pe, fieldItem.Name);
Expression GetPropertyExpression(Expression pe, string chain){
var properties = chain.Split('.');
foreach(var property in properties)
pe = Expression.Property(pe, property);
return pe;
}
基本上这段代码的作用是在每个创建 属性 链的循环上应用先前修改 pe
变量的属性。 Entity framework 将处理它并创建适当的连接。这仅适用于单一关系,不适用于集合。
因此该答案的修改代码如下所示:
public class FilterLinq<T>
{
Expression GetPropertyExpression(Expression pe, string chain)
{
var properties = chain.Split('.');
foreach(var property in properties)
pe = Expression.Property(pe, property);
return pe;
}
public static Expression<Func<T, Boolean>> GetWherePredicate(params SearchField[] SearchFieldList)
{
//the 'IN' parameter for expression ie T=> condition
ParameterExpression pe = Expression.Parameter(typeof(T), typeof(T).Name);
//combine them with and 1=1 Like no expression
Expression combined = null;
if (SearchFieldList != null)
{
foreach (var fieldItem in SearchFieldList)
{
//Expression for accessing Fields name property
Expression columnNameProperty = GetPropertyExpression(pe, fieldItem.Name);
//the name constant to match
Expression columnValue = Expression.Constant(fieldItem.Value);
//the first expression: PatientantLastName = ?
Expression e1 = Expression.Equal(columnNameProperty, columnValue);
if (combined == null)
{
combined = e1;
}
else
{
combined = Expression.And(combined, e1);
}
}
}
//create and return the predicate
return Expression.Lambda<Func<T, Boolean>>(combined, new ParameterExpression[] { pe });
}
}
我的模型如下所示
public class Country
{
public int Id {get; set;}
public string Name {get; set;}
}
public class User
{
public int Id{get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
public string Email {get; set;}
}
public class Company
{
public int Id{get; set;}
public string Name {get;set;}
public string City {get; set;}
public string Address1 {get; set;}
public string Address2 {get; set;}
[ForeignKey("Country")]
public int CountryId{get; set;}
public Country Country{get; set;}
public ICollection<CompanyUsers> CompanyUsers {get; set;}
}
public class CompanyUsers
{
public int Id{get; set;}
[ForeignKye("Company")]
public int CompanyId {get; set;}
[ForeignKye("User")]
public int UserId {get; set;}
public Country Country{get; set;}
public User User{get; set;}
}
我想让用户能够通过 Country, Company or User class
中定义的任何 属性 搜索公司记录,除了 Id 属性
我试着查看这个 SO discussion,但它不处理导航 属性。有人可以帮我构建动态 where 子句,包括导航属性 属性.
使用此实现我只能执行以下操作
myContext.CompanyEntity
.Where(FilterLinq<CompanyEntity>
.GetWherePredicate(searchParams))
.ToList();
public class SearchField
{
public string Key { get; set; }
public string Value { get; set; }
}
扩展您所指答案的想法并不那么复杂。
您需要更改假设,以便 SerchField 中的 属性 名称可以包含 属性 路径的定义,例如 Company.City
或 Company.Country.Name
以及 属性 FirstName
。而你需要处理它:
所以不要像这样简单地 属性:
Expression columnNameProperty = Expression.Property(pe, fieldItem.Name);
您需要处理 属性 链:
Expression columnNameProperty = GetPropertyExpression(pe, fieldItem.Name);
Expression GetPropertyExpression(Expression pe, string chain){
var properties = chain.Split('.');
foreach(var property in properties)
pe = Expression.Property(pe, property);
return pe;
}
基本上这段代码的作用是在每个创建 属性 链的循环上应用先前修改 pe
变量的属性。 Entity framework 将处理它并创建适当的连接。这仅适用于单一关系,不适用于集合。
因此该答案的修改代码如下所示:
public class FilterLinq<T>
{
Expression GetPropertyExpression(Expression pe, string chain)
{
var properties = chain.Split('.');
foreach(var property in properties)
pe = Expression.Property(pe, property);
return pe;
}
public static Expression<Func<T, Boolean>> GetWherePredicate(params SearchField[] SearchFieldList)
{
//the 'IN' parameter for expression ie T=> condition
ParameterExpression pe = Expression.Parameter(typeof(T), typeof(T).Name);
//combine them with and 1=1 Like no expression
Expression combined = null;
if (SearchFieldList != null)
{
foreach (var fieldItem in SearchFieldList)
{
//Expression for accessing Fields name property
Expression columnNameProperty = GetPropertyExpression(pe, fieldItem.Name);
//the name constant to match
Expression columnValue = Expression.Constant(fieldItem.Value);
//the first expression: PatientantLastName = ?
Expression e1 = Expression.Equal(columnNameProperty, columnValue);
if (combined == null)
{
combined = e1;
}
else
{
combined = Expression.And(combined, e1);
}
}
}
//create and return the predicate
return Expression.Lambda<Func<T, Boolean>>(combined, new ParameterExpression[] { pe });
}
}