The*_*uyu 5 c# specification-pattern entity-framework-core .net-core
我为我的 .net core 项目应用了规范模式。我还为包含、排序、分页等创建了自定义规范。
我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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
}
ISpecification.cs 接口
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; }
}
}
Run Code Online (Sandbox Code Playgroud)
基础规范.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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
规格评估器.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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
执行此操作的一个简单方法是使用反射按名称获取属性,然后构建表达式Expression<Func<PersonWithGroupsAndPrivileges, object>>。
让我们假设一个像这样的规范类:
public class BaseSpecification<T>
{
public Expression<Func<T, object>> OrderBy { get; private set; }
public Expression<Func<T, object>> OrderByDescending { get; private set; }
protected virtual void ApplyOrderBy(Expression<Func<T, object>> orderByExpression)
=> OrderBy = orderByExpression;
protected virtual void ApplyOrderByDescending(Expression<Func<T, object>> orderByDescendingExpression)
=> OrderByDescending = orderByDescendingExpression;
}
Run Code Online (Sandbox Code Playgroud)
这是一个完全工作的示例控制台项目,它实现一个PersonWithGroupsAndPrivileges<T>类并在类上使用它Person:
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace IssueConsoleTemplate
{
public class Person
{
public int PersonId { get; set; }
public string Gender { get; set; }
public string RoomNo { get; set; }
}
public class BaseSpecification<T>
{
public Expression<Func<T, object>> OrderBy { get; private set; }
public Expression<Func<T, object>> OrderByDescending { get; private set; }
protected virtual void ApplyOrderBy(Expression<Func<T, object>> orderByExpression)
=> OrderBy = orderByExpression;
protected virtual void ApplyOrderByDescending(Expression<Func<T, object>> orderByDescendingExpression)
=> OrderByDescending = orderByDescendingExpression;
protected void ApplySorting(string sort)
{
if(!string.IsNullOrEmpty(sort))
{
const string descendingSuffix = "Desc";
var descending = sort.EndsWith(descendingSuffix, StringComparison.Ordinal);
var propertyName = sort.Substring(0, 1).ToUpperInvariant() +
sort.Substring(1, sort.Length - 1 - (descending ? descendingSuffix.Length : 0));
var specificationType = GetType().BaseType;
var targetType = specificationType.GenericTypeArguments[0];
var property = targetType.GetRuntimeProperty(propertyName) ??
throw new InvalidOperationException($"Because the property {propertyName} does not exist it cannot be sorted.");
// Create an Expression<Func<T, object>>.
var lambdaParamX = Expression.Parameter(targetType, "x");
var propertyReturningExpression = Expression.Lambda(
Expression.Convert(
Expression.Property(lambdaParamX, property),
typeof(object)),
lambdaParamX);
if (descending)
{
specificationType.GetMethod(
nameof(ApplyOrderByDescending),
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Invoke(this, new object[]{propertyReturningExpression});
}
else
{
specificationType.GetMethod(
nameof(ApplyOrderBy),
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Invoke(this, new object[]{propertyReturningExpression});
}
}
}
}
public class PersonsWithGroupsAndPrivileges<T> : BaseSpecification<T>
{
public PersonsWithGroupsAndPrivileges(string sort)
{
ApplySorting(sort);
}
}
internal static class Program
{
private static void Main()
{
var p1 = new PersonsWithGroupsAndPrivileges<Person>("gender");
var p2 = new PersonsWithGroupsAndPrivileges<Person>("genderDesc");
}
}
}
Run Code Online (Sandbox Code Playgroud)
该代码适用于任何类T。
| 归档时间: |
|
| 查看次数: |
4685 次 |
| 最近记录: |