我申请了规范图案对于我的 .net 核心项目。
我还为包含、排序、分页等创建了自定义规范。
我得到 sort
来自带有 queryString 的 api url 的值并传递给自定义规范类。
在这个类中,我添加了一些 switch case
用于确定应该使用哪一列 orderBy
或 orderByDescending
但是该表中的列太多。那么有什么方法可以应用 sort
一次变量到所有列?还是我必须将所有列写入 switch
?
这是我的自定义规范类。
public class PersonsWithGroupsAndPrivileges : BaseSpecification<Person>
{
public PersonsWithGroupsAndPrivileges(string sort) : base()
{
AddInclude(x => x.Group);
AddInclude(x => x.Privilege);
if(!string.IsNullOrEmpty(sort))
{
switch (sort)
{
case "gender": ApplyOrderBy(x => x.Gender); break;
case "genderDesc": ApplyOrderByDescending(x => x.Gender); break;
case "roomNo": ApplyOrderBy(x => x.RoomNo); break;
case "roomNoDesc": ApplyOrderByDescending(x => x.RoomNo); break;
default: ApplyOrderBy(x => x.Name); break;
}
}
}
}ISpecification.cs 接口(interface)
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace XXXX.Core.Specifications
{
public interface ISpecification<T>
{
Expression<Func<T, bool>> Criteria { get; }
List<Expression<Func<T, object>>> Includes { get; }
List<string> IncludeStrings { get; }
Expression<Func<T, object>> OrderBy { get; }
Expression<Func<T, object>> OrderByDescending { get; }
Expression<Func<T, object>> GroupBy { get; }
int Take { get; }
int Skip { get; }
bool IsPagingEnabled { get; }
}
}
BaseSpecification.cs using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace XXXX.Core.Specifications
{
public abstract class BaseSpecification<T> : ISpecification<T>
{
protected BaseSpecification(Expression<Func<T, bool>> criteria)
{
Criteria = criteria;
}
protected BaseSpecification()
{
}
public Expression<Func<T, bool>> Criteria { get; }
public List<Expression<Func<T, object>>> Includes { get; } = new List<Expression<Func<T, object>>>();
public List<string> IncludeStrings { get; } = new List<string>();
public Expression<Func<T, object>> OrderBy { get; private set; }
public Expression<Func<T, object>> OrderByDescending { get; private set; }
public Expression<Func<T, object>> GroupBy { get; private set; }
public int Take { get; private set; }
public int Skip { get; private set; }
public bool IsPagingEnabled { get; private set; } = false;
protected virtual void AddInclude(Expression<Func<T, object>> includeExpression)
{
Includes.Add(includeExpression);
}
protected virtual void AddInclude(string includeString)
{
IncludeStrings.Add(includeString);
}
protected virtual void ApplyPaging(int skip, int take)
{
Skip = skip;
Take = take;
IsPagingEnabled = true;
}
protected virtual void ApplyOrderBy(Expression<Func<T, object>> orderByExpression)
{
OrderBy = orderByExpression;
}
protected virtual void ApplyOrderByDescending(Expression<Func<T, object>> orderByDescendingExpression)
{
OrderByDescending = orderByDescendingExpression;
}
protected virtual void ApplyGroupBy(Expression<Func<T, object>> groupByExpression)
{
GroupBy = groupByExpression;
}
}
}
SpecificationEvaluator.cs using System.Linq;
using DesTech.Core.Entities;
using DesTech.Core.Specifications;
using Microsoft.EntityFrameworkCore;
namespace XXXX.Infrastructure.Data
{
public class SpecificationEvaluator<TEntity> where TEntity : BaseEntity
{
public static IQueryable<TEntity> GetQuery(IQueryable<TEntity> inputQuery, ISpecification<TEntity> specification)
{
var query = inputQuery;
if (specification.Criteria != null)
{
query = query.Where(specification.Criteria);
}
query = specification.Includes.Aggregate(query, (current, include) => current.Include(include));
query = specification.IncludeStrings.Aggregate(query, (current, include) => current.Include(include));
if (specification.OrderBy != null)
{
query = query.OrderBy(specification.OrderBy);
}
else if (specification.OrderByDescending != null)
{
query = query.OrderByDescending(specification.OrderByDescending);
}
if (specification.GroupBy != null)
{
query = query.GroupBy(specification.GroupBy).SelectMany(x => x);
}
if (specification.IsPagingEnabled)
{
query = query.Skip(specification.Skip)
.Take(specification.Take);
}
return query;
}
}
}
最佳答案
您基本上需要两个辅助方法 - 一个从排序字符串中提取排序信息(名称和降序),另一个动态构建并应用 Expression<Func<T, object>>
从中。两者都进入基础泛型类。
第一个处理像 {property}[[ ]{Desc}]
这样的模式(不区分大小写)可能是这样的:
protected virtual void ExtractSortInfo(string sort, out string propertyPath, out bool descending)
{
const string Desc = "Desc";
propertyPath = sort;
descending = false;
if (propertyPath.EndsWith(Desc, StringComparison.OrdinalIgnoreCase))
{
propertyPath = sort.Substring(0, sort.Length - Desc.Length).TrimEnd();
descending = true;
}
}
第二个是这样的:public virtual void ApplySort(string sort)
{
if (string.IsNullOrEmpty(sort)) return;
ExtractSortInfo(sort, out var propertyPath, out var descending);
var parameter = Expression.Parameter(typeof(T), "x");
var body = propertyPath.Split('.').Aggregate((Expression)parameter, Expression.Property);
if (body.Type.IsValueType) body = Expression.Convert(body, typeof(object));
var selector = Expression.Lambda<Func<T, object>>(body, parameter);
if (descending)
ApplyOrderByDescending(selector);
else
ApplyOrderBy(selector);
}
另外,它支持点分隔的嵌套属性,如 blog.name
类(class) Person
有导航属性Blog
有属性(property)Name
.Expression.Convert
用于支持值类型(int
、decimal
、DateTime
等)属性
关于c# - EF Core 规范模式添加所有列以使用自定义规范对数据进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63082758/