Abp vNext 增删改查

Abp vNext 增删改查

  • Abp vNext 版本:5.3.3
    我会以我写过的其中一个项目的部分代码为例,这篇博客里出现的类我应该都有写出来,没写出来应该就是abp自带的,改个名称就好

目录

Abp vNext 基本使用
Abp vNext 增删改查
Abp vNext Token

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的实现就比较麻烦了,先把CreateDeleteUpdateGetById操作贴出来吧

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;
}

排序表达式

这是我跟着网上的资料写的,其实大部分都有相同的问题,就是OrderByOrderByDescendingThenByThenByDescending这几个方法是通过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; }
    }
}
posted @ 2022-10-12 16:59  .NET好耶  阅读(716)  评论(0编辑  收藏  举报