您好,我想使用实体创建一个动态搜索查询,并将 URI 中的值作为搜索字段。
下面的代码可以工作,但我必须搜索的一些表有超过 200 个字段,我想创建一些可以获取属性名称并允许我搜索的内容。
它还可以有多个搜索选项,例如姓氏和名字以及出生日期
queryable = queryable.Where(x => x.<PROPERTY.NAME>.Contains(query.<PROPERTY.NAME>));
这可能吗?
这是我到目前为止的代码。
public List<EMPLOYEE> Get([FromUri] EMPLOYEE query)
{
List<EMPLOYEE> emps = new List<EMPLOYEE>();
var db = AuthHandler.Ent;
var queryable = db.EMPLOYEES.AsExpandable();
foreach (var prop in query.GetType().GetProperties())
{
if (prop.GetValue(query, null) != null)
{
switch (prop.Name)
{
case "EMP_CREATIONDATE":
queryable = queryable.Where(x => x.EMP_CREATIONDATE.Equals(query.EMP_CREATIONDATE));
break;
case "EMP_SURNAME":
queryable = queryable.Where(x => x.EMP_SURNAME.Contains(query.EMP_SURNAME));
break;
case "EMP_GIVENNAMES":
queryable = queryable.Where(x => x.EMP_GIVENNAMES.Contains(query.EMP_GIVENNAMES));
break;
}
queryable = queryable.Where(x => x.EMP_SURNAME.Contains(query.EMP_SURNAME));
}
}
emps = queryable.ToList();
return emps;
}
我将使用这样的谓词构建器
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}
}
并像这样使用它:
public IQueryable<Customer> GetCustomers(CustomerOrderSearchParameters parameters)
{
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
var predicate = PredicateBuilder.True<Customer>();
if (!string.IsNullOrEmpty(parameters.FirstName))
{
predicate = predicate.And(x => x.FirstName.Contains(parameters.FirstName));
}
if (!string.IsNullOrEmpty(parameters.LastName))
{
predicate = predicate.And(x => x.LastName.Contains(parameters.LastName));
}
if (!string.IsNullOrEmpty(parameters.Email))
{
predicate = predicate.And(x => x.email.Contains(parameters.Email));
}
if (!string.IsNullOrEmpty(parameters.PhoneNumber))
{
predicate = predicate.And(x => x.MobilePhone.Contains(parameters.PhoneNumber) || x.HomePhone.Contains(parameters.PhoneNumber));
}
if (parameters.BrandID != null)
{
predicate = predicate.And(x => x.Logins.Where(l => l.BrandID == parameters.BrandID).Any());
}
if (parameters.ShowNoOrders == true)
{
predicate = predicate.And(x => x.Orders.Where(o => o.CustomerID != x.CustomerID).Any());
}
return context.Customers.AsExpandable().Where(predicate);
}
此外,
CustomerOrderSearchParameters
只是一个简单参数列表(相当于您从查询中获得的参数)
您可以使用
ObjectQuery
类和 Sql 运算符来构建动态查询,如下所示
public List<EMPLOYEE> Get([FromUri] EMPLOYEE query)
{
List<EMPLOYEE> emps = new List<EMPLOYEE>();
var db = AuthHandler.Ent;
var queryable = (ObjectQuery<EMPLOYEE>)db.EMPLOYEES.AsExpandable();
string condition = "CONTAINS(@column, @search)";
foreach (var prop in query.GetType().GetProperties())
{
var value = prop.GetValue(query, null);
if (value != null)
{
queryable = queryable.Where(string.Format(condition, prop.Name, value));
}
}
emps = queryable.ToList();
return emps;
}
我说得对吗?
我知道这个威胁已经很老了,可能已经有大量的库可供你使用,但它仍然可能对某人有所帮助:
[ApiController]
public class HrController : Controller
{
/*Housekeeping stuff*/
[HttpGet]
[Produces("application/json")]
[Route("api/[controller]/[action]/")]
public async Task<IActionResult> Persons()
{
List<Person> ppr = await _context.People
.AsNoTracking().ToListAsync();
if (HttpContext.Request.Query != null)
{
foreach (var query in HttpContext.Request.Query)
{
if (typeof(PeoplePoolResource).GetProperty(query.Key) != null)
{
if (query.Value.First() == null) continue;
if (query.Value.First().StartsWith('@')) //wildcard search
{
ppr = ppr.Where(a => a.GetType().GetProperty(query.Key).GetValue(a) != null &&
a.GetType().GetProperty(query.Key).GetValue(a).ToString().Contains(query.Value.First().Substring(1), System.StringComparison.OrdinalIgnoreCase)).ToList();
continue;
}
if (typeof(PeoplePoolResource).GetProperty(query.Key).PropertyType == typeof(int))
{
ppr = ppr.Where(a => (int)a.GetType().GetProperty(query.Key).GetValue(a) == int.Parse(query.Value)).ToList();
}
else if (typeof(PeoplePoolResource).GetProperty(query.Key).PropertyType == typeof(bool))
{
ppr = ppr.Where(a => (bool)a.GetType().GetProperty(query.Key).GetValue(a) == bool.Parse(query.Value)).ToList();
} //add other types like double
else
{
ppr = ppr.Where(a => a.GetType().GetProperty(query.Key).GetValue(a) != null &&
a.GetType().GetProperty(query.Key).GetValue(a).ToString().Equals(query.Value, System.StringComparison.OrdinalIgnoreCase)).ToList();
}
}
}
}
return Json(ppr);
}
}
然后您可以发送带有查询的 get 请求,如下所示:
http://localhost:50409/api/hr/persons?Id=252(这会让您找到
Id
252 的人)
http://localhost:50409/api/hr/persons?FirstName=@John(这会让您在其
FirstName
字段中包含字母John(不区分大小写)的所有人员
List<T>
并返回 List<T>
AND
搜索,不能更改为逻辑 OR
或其他。查看开源包 ServiceQuery。 http://ServiceQuery.com 它提供了一个动态表达式生成器,可以通过 REST API 服务序列化复杂的查询。
您的 API 服务:
using ServiceQuery;
[HttpPost]
[Route("ServiceQuery")]
public ServiceQueryResponse<ExampleTable> ServiceQuery(ServiceQueryRequest request)
{
var queryable = _context.ExampleTable.AsQueryable();
return request.Execute(queryable);
}
您的客户:
<script src="/js/servicequery.js"></script>
<script type="text/javascript">
function GetAll() {
var request = new ServiceQueryRequestBuilder()
.IsEqual("ID","1234").And().StartsWith("FirstName","John").Build();
$.ajax({
url: '/api/Example/ServiceQuery',
data: JSON.stringify(request),
type: "POST",
dataType: 'json',
headers: { 'Content-Type': 'application/json' },
success: function (result) {
alert(result.list.length + ' records returned');
}
});
}
</script>