Abp vNext 增删改查
Abp vNext 增删改查
- Abp vNext 版本:5.3.3
我会以我写过的其中一个项目的部分代码为例,这篇博客里出现的类我应该都有写出来,没写出来应该就是abp自带的,改个名称就好
目录
Model
首先,需要一个Model
,写点属性,继承聚合根就完事了
public class Menu : FullAuditedAggregateRoot<Guid>
{
/// <summary>
/// 菜单JSON字符串
/// </summary>
public string MenuStr { get; set; }
/// <summary>
/// 菜单所属角色Id
/// </summary>
public Guid? RoleId { get; set; }
public virtual Volo.Abp.Identity.IdentityRole Role { get; set; }
}
DbContext
添加配置
public DbSet<Menu> Menus { get; set; }
builder.Entity<Menu>(b =>
{
b.ToTable(UserCenterConsts.DbTablePrefix + nameof(Menu), UserCenterConsts.DbSchema);
b.ConfigureByConvention();
});
DTO
- 这个是进行
Create
操作时需要的dto
public class CreateMenuDto
{
public string MenuStr { get; set; }
public Guid? RoleId { get; set; }
}
-
Delete
操作只需要Id
即可 -
这个是进行
Update
操作时需要的dto
public class UpdateMenuDto
{
public string MenuStr { get; set; }
public Guid? RoleId { get; set; }
}
- 这个是用于返回给前端的dto
public class MenuDto : EntityDto<Guid>
{
public string MenuStr { get; set; }
public Guid? RoleId { get; set; }
}
Select
操作就比较麻烦了,简单的就是根据Id
查询,但是麻烦的就是分页、筛选、排序操作,因此这个需要dto
我这里是声明了一个包含分页、筛选、排序属性的基类,实际的dto只需要继承这个类即可
public class PageFilterAndSortDto
{
/// <summary>
/// 当前页数
/// </summary>
public int CurrentPage { get; set; }
/// <summary>
/// 每页的数据量
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// 筛选条件
/// </summary>
public List<FilterCondition> FilterConditionList { get; set; }
/// <summary>
/// 排序条件
/// </summary>
public List<SortCondition> SortConditionList { get; set; }
}
筛选条件
public class FilterCondition
{
/// <summary>
/// 筛选字段名
/// </summary>
public string FilterName { get; set; }
/// <summary>
/// 筛选数据
/// </summary>
public string FilterValue { get; set; }
/// <summary>
/// 筛选条件之间连接类型
/// </summary>
public FilterConditionConnectType FilterConditionConnectType { get; set; }
/// <summary>
/// 筛选字段的类型
/// </summary>
public FilterType FilterType { get; set; }
/// <summary>
/// 筛选的表达式类型
/// </summary>
public ExpressionType FilterExpressionType { get; set; }
}
public enum FilterConditionConnectType
{
And = 0,
Or = 1,
}
public enum FilterType
{
String = 0,
Int = 1,
Long = 2,
Boolean = 4,
DateTime = 8,
Guid = 16,
}
public enum ExpressionType
{
/// <summary>
/// like
/// </summary>
Contains = 0,
/// <summary>
/// 等于
/// </summary>
Equal = 1,
/// <summary>
/// 小于
/// </summary>
LessThan = 2,
/// <summary>
/// 小于等于
/// </summary>
LessThanOrEqual = 4,
/// <summary>
/// 大于
/// </summary>
GreaterThan = 8,
/// <summary>
/// 大于等于
/// </summary>
GreaterThanOrEqual = 16
}
排序条件
public class SortCondition
{
/// <summary>
/// 排序字段名
/// </summary>
public string SortName { get; set; }
/// <summary>
/// 排序类型
/// </summary>
public SortType SortType { get; set; }
}
public enum SortType
{
/// <summary>
/// 升序
/// </summary>
Asc = 0,
/// <summary>
/// 降序
/// </summary>
Desc = 1
}
最后就合成了这个Select
操作需要的dto
public class GetMenuListDto : PageFilterAndSortDto
{
}
配置dto
CreateMap<Menu, MenuDto>();
CreateMap<MenuDto, Menu>();
CreateMap<CreateMenuDto, Menu>();
CreateMap<UpdateMenuDto, Menu>();//感觉这条不大有用,因为转换到实体类型,但是Id不能手动修改,所以先查询才能修改数据
其实Abp中有分页、排序的DtoPagedAndSortedResultRequestDto
,但是没有筛选,可以继承这个再添加筛选条件,这样的话干脆用自定义的得了
Repository
声明接口
public interface IMenuRepository : IRepository<Menu, Guid>
{
}
实现接口
public class EfCoreMenuRepository : EfCoreRepository<UserCenterDbContext, Menu, Guid>, IMenuRepository
{
public EfCoreMenuRepository(IDbContextProvider<UserCenterDbContext> dbContextProvider) : base(dbContextProvider)
{
}
}
Service
声明接口
public interface IMenuAppService : IApplicationService
{
/// <summary>
/// 根据主键Id获取菜单
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<MenuDto> GetAsync(Guid id);
/// <summary>
/// 根据筛选参数获取菜单列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<PagedResultDto<MenuDto>> GetListAsync(GetMenuListDto input);
/// <summary>
/// 创建菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<MenuDto> CreateAsync(CreateMenuDto input);
/// <summary>
/// 修改菜单
/// </summary>
/// <param name="id"></param>
/// <param name="input"></param>
/// <returns></returns>
Task<MenuDto> UpdateAsync(Guid id, UpdateMenuDto input);
/// <summary>
/// 删除菜单
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task DeleteAsync(Guid id);
/// <summary>
/// 批量删除菜单
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
Task DeleteAsync(List<Guid> ids);
}
这个Service的实现就比较麻烦了,先把Create
、Delete
、Update
、GetById
操作贴出来吧
public class MenuAppService : UserCenterAppService, IMenuAppService
{
private readonly IMenuRepository _menuRepository;
private readonly IAsyncQueryableExecuter _asyncExecuter;
public MenuAppService(IMenuRepository menuRepository, IAsyncQueryableExecuter queryableExecuter)
{
this._menuRepository = menuRepository;
this._queryableExecuter = queryableExecuter;
}
public async Task<MenuDto> CreateAsync(CreateMenuDto input)
{
var menu = ObjectMapper.Map<CreateMenuDto, Menu>(input);
await this._menuRepository.InsertAsync(menu);
return ObjectMapper.Map<Menu, MenuDto>(menu);
}
public async Task DeleteAsync(Guid id)
{
await this._menuRepository.DeleteAsync(id);
}
public async Task DeleteAsync(List<Guid> ids)
{
await this._menuRepository.DeleteManyAsync(ids);
}
public async Task<MenuDto> GetAsync(Guid id)
{
var menu = await this._menuRepository.GetAsync(id);
return ObjectMapper.Map<Menu, MenuDto>(menu);
}
public async Task<MenuDto> UpdateAsync(Guid id, UpdateMenuDto input)
{
var menu = await this._menuRepository.GetAsync(id);
menu.MenuStr = input.MenuStr;
menu.RoleId = input.RoleId;
var menuDto = ObjectMapper.Map<Menu, MenuDto>(await this._menuRepository.UpdateAsync(menu));
return menuDto;
}
}
Update
操作其实是问题的,因为实体类里有个ConcurrencyStamp
属性,这个是锁,update操作会校验这个数据,如果实体类配置里没有这个属性,则可以随意操作,因为abp是事务操作,所以一般不用担心数据冲突,这个锁是用于分布式的
拼接 Linq 语句
我想到的解决方法是拼接Linq语句
先声明一个通用的Service,给子类Service保留一个获取IQueryable
的函数
public class BaseAppService<TEntity> : UserCenterAppService where TEntity : class
{
protected readonly IAsyncQueryableExecuter _queryableExecuter;
public BaseAppService(IAsyncQueryableExecuter queryableExecuter)
{
this._queryableExecuter = queryableExecuter;
}
/// <summary>
/// 获取分页、过滤、排序IQueryable
/// </summary>
/// <param name="dto">分页、过滤、排序Dto</param>
/// <param name="queryable">存储类型获取的IQueryable</param>
/// <returns></returns>
protected IQueryable<TEntity> GetPageFilterAndSortQueryable(PageFilterAndSortDto dto, IQueryable<TEntity> queryable)
{
}
}
子类就这样继承
public class MenuAppService : BaseAppService<Menu>, IMenuAppService
{
private readonly IMenuRepository _menuRepository;
public MenuAppService(IMenuRepository menuRepository, IAsyncQueryableExecuter queryableExecuter) : base(queryableExecuter)
{
this._menuRepository = menuRepository;
}
}
然后写一个Helper
类来拼接这个Linq表达式,我也是看了挺多博客才写出来的
public class PageFilterAndSortLambdaHelper<TEntity> where TEntity : class
{
}
筛选表达式
先是拼接筛选的表达式,就是根据条件一句一句拼接
private class WhereExpression
{
/// <summary>
/// 筛选条件的表达式
/// </summary>
public Expression Expression { get; set; }
/// <summary>
/// 筛选条件的连接类型
/// </summary>
public FilterConditionConnectType FilterConditionConnectType { get; set; }
}
/// <summary>
/// 加载where表达式
/// </summary>
/// <param name="whereExpressionList">表达式列表</param>
/// <param name="parameterExpression">参数表达式</param>
/// <param name="filterCondition">where条件</param>
private static void LoadWhereExpression(List<WhereExpression> whereExpressionList, ParameterExpression parameterExpression, FilterCondition filterCondition)
{
Expression expression = null;
//x.字段名称
MemberExpression memberExpression = Expression.PropertyOrField(parameterExpression, filterCondition.FilterName);
//获取数值
object value = null;
//类型转换
switch (filterCondition.FilterType)
{
case Models.FilterType.String:
value = filterCondition.FilterValue;
break;
case Models.FilterType.Int:
value = int.Parse(filterCondition.FilterValue);
break;
case Models.FilterType.Long:
value = long.Parse(filterCondition.FilterValue);
break;
case Models.FilterType.Boolean:
value = filterCondition.FilterValue.ToUpper() == "TRUE" ? true : false;
break;
case Models.FilterType.DateTime:
value = Convert.ToDateTime(filterCondition.FilterValue);
break;
case Models.FilterType.Guid:
value = new Guid(filterCondition.FilterValue);
break;
default:
value = filterCondition.FilterValue;
break;
}
//根据表达式类型生成语句
switch (filterCondition.FilterExpressionType)
{
case Models.ExpressionType.Contains:
expression = Expression.Call(memberExpression, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(value));
break;
case Models.ExpressionType.Equal:
expression = Expression.Equal(memberExpression, Expression.Constant(value, memberExpression.Type));
break;
case Models.ExpressionType.LessThan:
expression = Expression.LessThan(memberExpression, Expression.Constant(value, memberExpression.Type));
break;
case Models.ExpressionType.LessThanOrEqual:
expression = Expression.LessThanOrEqual(memberExpression, Expression.Constant(value, memberExpression.Type));
break;
case Models.ExpressionType.GreaterThan:
expression = Expression.GreaterThan(memberExpression, Expression.Constant(value, memberExpression.Type));
break;
case Models.ExpressionType.GreaterThanOrEqual:
expression = Expression.GreaterThanOrEqual(memberExpression, Expression.Constant(value, memberExpression.Type));
break;
default:
break;
}
whereExpressionList.Add(new WhereExpression()
{
Expression = expression,
FilterConditionConnectType = filterCondition.FilterConditionConnectType
});
}
/// <summary>
/// 获取where表达式
/// </summary>
/// <param name="pageFilterAndSortDto">分页、筛选、排序Dto对象</param>
/// <returns></returns>
private static Expression<Func<TEntity, bool>> GetWhereExpression(PageFilterAndSortDto pageFilterAndSortDto)
{
List<WhereExpression> whereExpressionList = new List<WhereExpression>();
ParameterExpression parameterExpression = Expression.Parameter(typeof(TEntity), "x");
//加载where表达式
foreach (var filterCondition in pageFilterAndSortDto.FilterConditionList)
{
if (true == string.IsNullOrWhiteSpace(filterCondition.FilterName) || true == string.IsNullOrWhiteSpace(filterCondition.FilterValue))
{
continue;
}
PageFilterAndSortLambdaHelper<TEntity>.LoadWhereExpression(whereExpressionList, parameterExpression, filterCondition);
}
//返回where表达式
Expression expression = null;
foreach (var item in whereExpressionList)
{
if (null == expression)
{
expression = item.Expression;
}
else
{
//这里拼接条件 And 或 Or
//And一般就够用了
switch (item.FilterConditionConnectType)
{
case FilterConditionConnectType.And:
expression = Expression.And(expression, item.Expression);
break;
case FilterConditionConnectType.Or:
expression = Expression.Or(expression, item.Expression);
break;
default:
break;
}
}
}
if (null == expression)
{
return null;
}
return Expression.Lambda<Func<TEntity, bool>>(expression, parameterExpression);
}
/// <summary>
/// 获取筛选后的IQueryable对象
/// </summary>
/// <param name="pageFilterAndSortDto">分页、筛选、过滤Dto对象</param>
/// <param name="queryable">最初的IQueryable对象</param>
/// <returns></returns>
public static IQueryable<TEntity> GetWhereQueryable(PageFilterAndSortDto pageFilterAndSortDto, IQueryable<TEntity> queryable)
{
if (null == pageFilterAndSortDto.FilterConditionList)
{
return queryable;
}
Expression sourceExpression = queryable.Expression;
Expression whereExpression = PageFilterAndSortLambdaHelper<TEntity>.GetWhereExpression(pageFilterAndSortDto);
if (null == whereExpression)
{
return queryable;
}
//获取完表达式,就用Where调用
whereExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { typeof(TEntity) }, sourceExpression, whereExpression);
IQueryable<TEntity> whereQueryable = queryable.Provider.CreateQuery<TEntity>(whereExpression);
return whereQueryable;
}
排序表达式
这是我跟着网上的资料写的,其实大部分都有相同的问题,就是OrderBy
、OrderByDescending
、ThenBy
、ThenByDescending
这几个方法是通过Expression.Call
反射调用的,而这几个方法的有静态、重载、泛型,还是扩展方法,反射是不能直接获取,我用了好几种方法都不行,倒是可以通过获取方法集合,再筛选出这个方法,但是有性能问题,所以我是在Helper类中声明private readonly static
和静态构造器解决问题
private readonly static MethodInfo _orderByMethodInfo;
private readonly static MethodInfo _orderByDescendingMethodInfo;
private readonly static MethodInfo _thenByMethodInfo;
private readonly static MethodInfo _thenByDescendingMethodInfo;
static PageFilterAndSortLambdaHelper()
{
Type type = typeof(Queryable);
//反射获取泛型方法
//不能通过方法名直接获取
_orderByMethodInfo = type.GetMethods()
.Single(x => String.Equals(x.Name, "OrderBy", StringComparison.Ordinal)
&& true == x.IsGenericMethodDefinition//方法为泛型定义
&& 2 == x.GetGenericArguments().Length//方法的泛型参数个数
&& 2 == x.GetParameters().Length);//方法的参数个数
_orderByDescendingMethodInfo = type.GetMethods()
.Single(x => String.Equals(x.Name, "OrderByDescending", StringComparison.Ordinal)
&& true == x.IsGenericMethodDefinition//方法为泛型定义
&& 2 == x.GetGenericArguments().Length//方法的泛型参数个数
&& 2 == x.GetParameters().Length);//方法的参数个数
_thenByMethodInfo = type.GetMethods()
.Single(x => String.Equals(x.Name, "ThenBy", StringComparison.Ordinal)
&& true == x.IsGenericMethodDefinition//方法为泛型定义
&& 2 == x.GetGenericArguments().Length//方法的泛型参数个数
&& 2 == x.GetParameters().Length);//方法的参数个数
_thenByDescendingMethodInfo = type.GetMethods()
.Single(x => String.Equals(x.Name, "ThenByDescending", StringComparison.Ordinal)
&& true == x.IsGenericMethodDefinition//方法为泛型定义
&& 2 == x.GetGenericArguments().Length//方法的泛型参数个数
&& 2 == x.GetParameters().Length);//方法的参数个数
}
/// <summary>
/// 获取排序后的IQueryable对象
/// </summary>
/// <param name="pageFilterAndSortDto">分页、筛选、排序Dto对象</param>
/// <param name="queryable">筛选后的IQueryable对象</param>
/// <returns>返回排序后的IQueryable对象</returns>
public static IQueryable<TEntity> GetSortQueryable(PageFilterAndSortDto pageFilterAndSortDto, IQueryable<TEntity> queryable)
{
object query = queryable as object;
ParameterExpression parameterExpression = Expression.Parameter(typeof(TEntity), "x");
//加载sort表达式
if (null != pageFilterAndSortDto.SortConditionList)
{
//用来判断是否第一次调用排序方法 OrderBy ThenBy
bool isFirst = true;
foreach (var sortCondition in pageFilterAndSortDto.SortConditionList)
{
if (true == string.IsNullOrWhiteSpace(sortCondition.SortName))
{
continue;
}
//x.字段名称
MemberExpression memberExpression = Expression.PropertyOrField(parameterExpression, sortCondition.SortName);
//x=>x.字段名称
LambdaExpression lambdaExpression = Expression.Lambda(memberExpression, parameterExpression);
//通过反射调用排序方法
switch (sortCondition.SortType)
{
case Models.SortType.Asc:
if (true == isFirst)
{
//给泛型方法设置类型
MethodInfo methodInfo = _orderByMethodInfo.MakeGenericMethod(typeof(TEntity), memberExpression.Type);
//输入参数并调用泛型方法
query = methodInfo.Invoke(null, new object[] { query, lambdaExpression });
}
else
{
//给泛型方法设置类型
MethodInfo methodInfo = _thenByMethodInfo.MakeGenericMethod(typeof(TEntity), memberExpression.Type);
//输入参数并调用泛型方法
query = methodInfo.Invoke(null, new object[] { query, lambdaExpression });
}
break;
case Models.SortType.Desc:
if (true == isFirst)
{
//给泛型方法设置类型
MethodInfo methodInfo = _orderByDescendingMethodInfo.MakeGenericMethod(typeof(TEntity), memberExpression.Type);
//输入参数并调用泛型方法
query = methodInfo.Invoke(null, new object[] { query, lambdaExpression });
}
else
{
//给泛型方法设置类型
MethodInfo methodInfo = _thenByDescendingMethodInfo.MakeGenericMethod(typeof(TEntity), memberExpression.Type);
//输入参数并调用泛型方法
query = methodInfo.Invoke(null, new object[] { query, lambdaExpression });
}
break;
default:
break;
}
isFirst = false;
}
}
return query as IQueryable<TEntity>;
}
至于为什么不用IOrderedQueryable
,因为如果排序条件的集合中的个数为0,那么就不会进行排序,最后的类型转换会失败,多一次判空太麻烦了
分页表达式
这个最简单
/// <summary>
/// 获取分页后的IQueryable
/// </summary>
/// <param name="pageFilterAndSortDto">分页、筛选、排序Dto对象</param>
/// <param name="queryable">筛选、排序后的IQueryable对象</param>
/// <returns></returns>
public static IQueryable<TEntity> GetPageQueryable(PageFilterAndSortDto pageFilterAndSortDto, IQueryable<TEntity> queryable)
{
//当前页数和每页的数据量大于等于0就执行分页操作
if (pageFilterAndSortDto.CurrentPage >= 0 && pageFilterAndSortDto.PageSize >= 0)
{
return queryable.Skip((pageFilterAndSortDto.CurrentPage - 1) * pageFilterAndSortDto.PageSize).Take(pageFilterAndSortDto.PageSize);
}
//为负数则获取所有数据
return queryable;
}
构建基础服务类
public class BaseAppService<TEntity> : UserCenterAppService where TEntity : class
{
protected readonly IAsyncQueryableExecuter _queryableExecuter;
public BaseAppService(IAsyncQueryableExecuter queryableExecuter)
{
this._queryableExecuter = queryableExecuter;
}
/// <summary>
/// 获取筛选数据的总数
/// </summary>
/// <param name="dto">分页、筛选、排序Dto</param>
/// <param name="queryable">IRepository类型获取的Queryable</param>
/// <returns>返回筛选数据的总数</returns>
protected long GetFilterTotalCount(PageFilterAndSortDto dto, IQueryable<TEntity> queryable)
{
//拼接条件 where
IQueryable<TEntity> whereQueryable = PageFilterAndSortLambdaHelper<TEntity>.GetWhereQueryable(dto, queryable);
long count = whereQueryable.LongCount();
return count;
}
/// <summary>
/// 获取分页、筛选、排序IQueryable
/// </summary>
/// <param name="dto">分页、筛选、排序Dto</param>
/// <param name="queryable">IRepository类型获取的Queryable</param>
/// <returns>返回筛选、排序、分页之后的IQueryable</returns>
protected IQueryable<TEntity> GetPageFilterAndSortQueryable(PageFilterAndSortDto dto, IQueryable<TEntity> queryable)
{
//拼接条件 where
IQueryable<TEntity> whereQueryable = PageFilterAndSortLambdaHelper<TEntity>.GetWhereQueryable(dto, queryable);
//拼接排序 sort
IOrderedQueryable<TEntity> sortedQuery = PageFilterAndSortLambdaHelper<TEntity>.GetSortQueryable(dto, whereQueryable);
//拼接分页 page
IQueryable<TEntity> pagedQuery = PageFilterAndSortLambdaHelper<TEntity>.GetPageQueryable(dto, sortedQuery);
return pagedQuery;
}
}
完整实体服务类
最后调用即可
public class MenuAppService : BaseAppService<Menu>, IMenuAppService
{
private readonly IMenuRepository _menuRepository;
public MenuAppService(IMenuRepository menuRepository, IAsyncQueryableExecuter queryableExecuter) : base(queryableExecuter)
{
this._menuRepository = menuRepository;
}
public async Task<MenuDto> CreateAsync(CreateMenuDto input)
{
var menu = ObjectMapper.Map<CreateMenuDto, Menu>(input);
await this._menuRepository.InsertAsync(menu);
return ObjectMapper.Map<Menu, MenuDto>(menu);
}
public async Task DeleteAsync(Guid id)
{
await this._menuRepository.DeleteAsync(id);
}
public async Task DeleteAsync(List<Guid> ids)
{
await this._menuRepository.DeleteManyAsync(ids);
}
public async Task<MenuDto> GetAsync(Guid id)
{
var menu = await this._menuRepository.GetAsync(id);
return ObjectMapper.Map<Menu, MenuDto>(menu);
}
public async Task<PagedResultDto<MenuDto>> GetListAsync(GetMenuListDto input)
{
IQueryable<Menu> baseQueryable = await this._menuRepository.GetQueryableAsync();
IQueryable<Menu> queryable = base.GetPageFilterAndSortQueryable(input, baseQueryable);
List<Menu> list = queryable.ToList();
long count = base.GetFilterTotalCount(input, baseQueryable);
return new PagedResultDto<MenuDto>()
{
TotalCount = count,
Items = ObjectMapper.Map<List<Menu>, List<MenuDto>>(list)
};
}
public async Task<MenuDto> UpdateAsync(Guid id, UpdateMenuDto input)
{
var menu = await this._menuRepository.GetAsync(id);
menu.MenuStr = input.MenuStr;
menu.RoleId = input.RoleId;
var menuDto = ObjectMapper.Map<Menu, MenuDto>(await this._menuRepository.UpdateAsync(menu));
return menuDto;
}
}
Controller
虽说Abp有Auto API,不过我还是手写了
[ApiController]
[Route("/api/v1/[controller]")]
public class MenuController : AbpControllerBase
{
private readonly IMenuAppService _menuAppService;
public MenuController(IMenuAppService menuAppService)
{
this._menuAppService = menuAppService;
}
[HttpGet("GetOne/{id}")]
public async Task<ActionResult<MenuDto>> GetOne([FromRoute] string id)
{
var menuDto = await this._menuAppService.GetAsync(Guid.Parse(id));
return Ok(menuDto);
}
[HttpPost("GetList")]
public async Task<ActionResult<PagedResultDto<MenuDto>>> GetList([FromBody] GetMenuListDto input)
{
var list = await this._menuAppService.GetListAsync(input);
return Ok(list);
}
[HttpPost("Create")]
public async Task<ActionResult<MenuDto>> Create([FromBody] CreateMenuDto input)
{
var menuDto = await this._menuAppService.CreateAsync(input);
return Ok(menuDto);
}
[HttpPut("Update/{id}")]
public async Task<ActionResult<MenuDto>> Update([FromRoute] string id, [FromBody] UpdateMenuDto input)
{
var menuDto = await this._menuAppService.UpdateAsync(Guid.Parse(id), input);
return Ok(menuDto);
}
[HttpDelete("Delete/{id}")]
public async Task<IActionResult> Delete([FromRoute] string id)
{
await this._menuAppService.DeleteAsync(Guid.Parse(id));
return Ok();
}
[HttpDelete("Delete")]
public async Task<IActionResult> Delete([FromBody] List<string> ids)
{
List<Guid> guids = ids.Select(x => Guid.Parse(x)).ToList();
await this._menuAppService.DeleteAsync(guids);
return Ok();
}
}
在Update操作的地方,可以把Id放到UpdateDto里,我比较习惯单独放Id,只是个习惯
Abp vNext 增删改查 结束
PageFilterAndSortLambdaHelper
完整代码
public class PageFilterAndSortLambdaHelper<TEntity> where TEntity : class
{
private readonly static MethodInfo _orderByMethodInfo;
private readonly static MethodInfo _orderByDescendingMethodInfo;
private readonly static MethodInfo _thenByMethodInfo;
private readonly static MethodInfo _thenByDescendingMethodInfo;
static PageFilterAndSortLambdaHelper()
{
Type type = typeof(Queryable);
//反射获取泛型方法
//不能通过方法名直接获取
_orderByMethodInfo = type.GetMethods()
.Single(x => String.Equals(x.Name, "OrderBy", StringComparison.Ordinal)
&& true == x.IsGenericMethodDefinition//方法为泛型定义
&& 2 == x.GetGenericArguments().Length//方法的泛型参数个数
&& 2 == x.GetParameters().Length);//方法的参数个数
_orderByDescendingMethodInfo = type.GetMethods()
.Single(x => String.Equals(x.Name, "OrderByDescending", StringComparison.Ordinal)
&& true == x.IsGenericMethodDefinition//方法为泛型定义
&& 2 == x.GetGenericArguments().Length//方法的泛型参数个数
&& 2 == x.GetParameters().Length);//方法的参数个数
_thenByMethodInfo = type.GetMethods()
.Single(x => String.Equals(x.Name, "ThenBy", StringComparison.Ordinal)
&& true == x.IsGenericMethodDefinition//方法为泛型定义
&& 2 == x.GetGenericArguments().Length//方法的泛型参数个数
&& 2 == x.GetParameters().Length);//方法的参数个数
_thenByDescendingMethodInfo = type.GetMethods()
.Single(x => String.Equals(x.Name, "ThenByDescending", StringComparison.Ordinal)
&& true == x.IsGenericMethodDefinition//方法为泛型定义
&& 2 == x.GetGenericArguments().Length//方法的泛型参数个数
&& 2 == x.GetParameters().Length);//方法的参数个数
}
/// <summary>
/// 加载where表达式
/// </summary>
/// <param name="whereExpressionList">表达式列表</param>
/// <param name="parameterExpression">参数表达式</param>
/// <param name="filterCondition">where条件</param>
private static void LoadWhereExpression(List<WhereExpression> whereExpressionList, ParameterExpression parameterExpression, FilterCondition filterCondition)
{
Expression expression = null;
//x.字段名称
MemberExpression memberExpression = Expression.PropertyOrField(parameterExpression, filterCondition.FilterName);
//获取数值
object value = null;
//类型转换
switch (filterCondition.FilterType)
{
case Models.FilterType.String:
value = filterCondition.FilterValue;
break;
case Models.FilterType.Int:
value = int.Parse(filterCondition.FilterValue);
break;
case Models.FilterType.Long:
value = long.Parse(filterCondition.FilterValue);
break;
case Models.FilterType.Boolean:
value = filterCondition.FilterValue.ToUpper() == "TRUE" ? true : false;
break;
case Models.FilterType.DateTime:
value = Convert.ToDateTime(filterCondition.FilterValue);
break;
case Models.FilterType.Guid:
value = new Guid(filterCondition.FilterValue);
break;
default:
value = filterCondition.FilterValue;
break;
}
//根据表达式类型生成语句
switch (filterCondition.FilterExpressionType)
{
case Models.ExpressionType.Contains:
expression = Expression.Call(memberExpression, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(value));
break;
case Models.ExpressionType.Equal:
expression = Expression.Equal(memberExpression, Expression.Constant(value, memberExpression.Type));
break;
case Models.ExpressionType.LessThan:
expression = Expression.LessThan(memberExpression, Expression.Constant(value, memberExpression.Type));
break;
case Models.ExpressionType.LessThanOrEqual:
expression = Expression.LessThanOrEqual(memberExpression, Expression.Constant(value, memberExpression.Type));
break;
case Models.ExpressionType.GreaterThan:
expression = Expression.GreaterThan(memberExpression, Expression.Constant(value, memberExpression.Type));
break;
case Models.ExpressionType.GreaterThanOrEqual:
expression = Expression.GreaterThanOrEqual(memberExpression, Expression.Constant(value, memberExpression.Type));
break;
default:
break;
}
whereExpressionList.Add(new WhereExpression()
{
Expression = expression,
FilterConditionConnectType = filterCondition.FilterConditionConnectType
});
}
/// <summary>
/// 获取where表达式
/// </summary>
/// <param name="pageFilterAndSortDto">分页、筛选、排序Dto对象</param>
/// <returns></returns>
private static Expression<Func<TEntity, bool>> GetWhereExpression(PageFilterAndSortDto pageFilterAndSortDto)
{
List<WhereExpression> whereExpressionList = new List<WhereExpression>();
ParameterExpression parameterExpression = Expression.Parameter(typeof(TEntity), "x");
//加载where表达式
foreach (var filterCondition in pageFilterAndSortDto.FilterConditionList)
{
if (true == string.IsNullOrWhiteSpace(filterCondition.FilterName) || true == string.IsNullOrWhiteSpace(filterCondition.FilterValue))
{
continue;
}
PageFilterAndSortLambdaHelper<TEntity>.LoadWhereExpression(whereExpressionList, parameterExpression, filterCondition);
}
//返回where表达式
Expression expression = null;
foreach (var item in whereExpressionList)
{
if (null == expression)
{
expression = item.Expression;
}
else
{
//这里拼接条件 And 或 Or
//And一般就够用了
switch (item.FilterConditionConnectType)
{
case FilterConditionConnectType.And:
expression = Expression.And(expression, item.Expression);
break;
case FilterConditionConnectType.Or:
expression = Expression.Or(expression, item.Expression);
break;
default:
break;
}
}
}
if (null == expression)
{
return null;
}
return Expression.Lambda<Func<TEntity, bool>>(expression, parameterExpression);
}
/// <summary>
/// 获取筛选后的IQueryable对象
/// </summary>
/// <param name="pageFilterAndSortDto">分页、筛选、过滤Dto对象</param>
/// <param name="queryable">最初的IQueryable对象</param>
/// <returns></returns>
public static IQueryable<TEntity> GetWhereQueryable(PageFilterAndSortDto pageFilterAndSortDto, IQueryable<TEntity> queryable)
{
if (null == pageFilterAndSortDto.FilterConditionList)
{
return queryable;
}
Expression sourceExpression = queryable.Expression;
Expression whereExpression = PageFilterAndSortLambdaHelper<TEntity>.GetWhereExpression(pageFilterAndSortDto);
if (null == whereExpression)
{
return queryable;
}
//获取完表达式,就用Where调用
whereExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { typeof(TEntity) }, sourceExpression, whereExpression);
IQueryable<TEntity> whereQueryable = queryable.Provider.CreateQuery<TEntity>(whereExpression);
return whereQueryable;
}
/// <summary>
/// 获取排序后的IQueryable对象
/// </summary>
/// <param name="pageFilterAndSortDto">分页、筛选、排序Dto对象</param>
/// <param name="queryable">筛选后的IQueryable对象</param>
/// <returns>返回排序后的IQueryable对象</returns>
public static IQueryable<TEntity> GetSortQueryable(PageFilterAndSortDto pageFilterAndSortDto, IQueryable<TEntity> queryable)
{
object query = queryable as object;
ParameterExpression parameterExpression = Expression.Parameter(typeof(TEntity), "x");
//加载sort表达式
if (null != pageFilterAndSortDto.SortConditionList)
{
//用来判断是否第一次调用排序方法 OrderBy ThenBy
bool isFirst = true;
foreach (var sortCondition in pageFilterAndSortDto.SortConditionList)
{
if (true == string.IsNullOrWhiteSpace(sortCondition.SortName))
{
continue;
}
//x.字段名称
MemberExpression memberExpression = Expression.PropertyOrField(parameterExpression, sortCondition.SortName);
//x=>x.字段名称
LambdaExpression lambdaExpression = Expression.Lambda(memberExpression, parameterExpression);
//通过反射调用排序方法
switch (sortCondition.SortType)
{
case Models.SortType.Asc:
if (true == isFirst)
{
//给泛型方法设置类型
MethodInfo methodInfo = _orderByMethodInfo.MakeGenericMethod(typeof(TEntity), memberExpression.Type);
//输入参数并调用泛型方法
query = methodInfo.Invoke(null, new object[] { query, lambdaExpression });
}
else
{
//给泛型方法设置类型
MethodInfo methodInfo = _thenByMethodInfo.MakeGenericMethod(typeof(TEntity), memberExpression.Type);
//输入参数并调用泛型方法
query = methodInfo.Invoke(null, new object[] { query, lambdaExpression });
}
break;
case Models.SortType.Desc:
if (true == isFirst)
{
//给泛型方法设置类型
MethodInfo methodInfo = _orderByDescendingMethodInfo.MakeGenericMethod(typeof(TEntity), memberExpression.Type);
//输入参数并调用泛型方法
query = methodInfo.Invoke(null, new object[] { query, lambdaExpression });
}
else
{
//给泛型方法设置类型
MethodInfo methodInfo = _thenByDescendingMethodInfo.MakeGenericMethod(typeof(TEntity), memberExpression.Type);
//输入参数并调用泛型方法
query = methodInfo.Invoke(null, new object[] { query, lambdaExpression });
}
break;
default:
break;
}
isFirst = false;
}
}
return query as IQueryable<TEntity>;
}
/// <summary>
/// 获取分页后的IQueryable
/// </summary>
/// <param name="pageFilterAndSortDto">分页、筛选、排序Dto对象</param>
/// <param name="queryable">筛选、排序后的IQueryable对象</param>
/// <returns></returns>
public static IQueryable<TEntity> GetPageQueryable(PageFilterAndSortDto pageFilterAndSortDto, IQueryable<TEntity> queryable)
{
//当前页数和每页的数据量大于等于0就执行分页操作
if (pageFilterAndSortDto.CurrentPage >= 0 && pageFilterAndSortDto.PageSize >= 0)
{
return queryable.Skip((pageFilterAndSortDto.CurrentPage - 1) * pageFilterAndSortDto.PageSize).Take(pageFilterAndSortDto.PageSize);
}
//为负数则获取所有数据
return queryable;
}
private class WhereExpression
{
/// <summary>
/// 筛选条件的表达式
/// </summary>
public Expression Expression { get; set; }
/// <summary>
/// 筛选条件的连接类型
/// </summary>
public FilterConditionConnectType FilterConditionConnectType { get; set; }
}
}