• EF查询 常用IQueryable<T>拓展


    背景

    日常使用EF查询数据时,经常会用到筛选(where),排序(sort),分页(skip take)等操作。

    举个简单例子

    var list = dbContext.Students.Where(d => true);//筛选
    if (!string.IsNullOrWhiteSpace(query.Name))
    {
        list = list.Where(d => d.Name.Contains(query.Name));
    }
    if (!string.IsNullOrWhiteSpace(query.Remark))
    {
        list = list.Where(d => d.Remark.Contains(query.Remark));
    }
    //...
     var result = list.OrderBy(d => d.Id)//排序
                    .Skip((query.PageIndex - 1) * query.PageSize).Take(query.PageSize)//分页
                    .ToList();//从数据库取出数据
    
    //获取单个实体的Name属性
    var student = list.FirstOrDefault(d=>d.Name.Contains(query.Name));
    var name = "";
    if (student != null)
    {
        name = student.Name;
    }
    

    常常感觉重复性的代码过多,占用的篇幅不小,想点办法解决一下。

    解决方案

    where语句:封装WhereIf拓展方法,只有当指定的condition成立时,才执行predicate语句。

    需要注意IQueryableIEnumerableWhere方法的参数不同(Expression表达式语句)实际用法是一样的。

    public static IQueryable<T> WhereIf<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate, bool condition)
    {
        if (condition)
        {
            source = source.Where(predicate);
        }
        return source;
    }
    public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, Func<T, bool> predicate, bool condition)
    {
        if (condition)
        {
            source = source.Where(predicate);
        }
        return source;
    }
    

    Page语句:简单封装下IQueryableIEnumerable分页方法,只是精简了一下而已。

    public static IQueryable<T> DataPage<T>(this IQueryable<T> source, int pageNumber, int pageSize)
    {
        if (pageNumber <= 1)
        {
            if (pageSize == int.MaxValue)
            {
                return source;
            }
            return source.Take(pageSize);
        }
        else
        {
            return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
        }
    }
    

    Sort语句:通过拼接Sort排序字符串 这里需要引入一个System.Linq.Dynamic.Core,支持查询字符串拼接,进行动态查询。

    public static IQueryable<T> DataSort<T>(this IQueryable<T> source, string sortExpression)
    {
        try
        {
            var sortStrs = sortExpression.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            var defaultOrder = "desc";
            if (sortStrs.Length == 2)
            {
                defaultOrder = sortStrs[1];
            }
            if (typeof(T).GetProperty("Id") != null && sortStrs[0] != "Id")
            {
                source = source.OrderBy(sortStrs[0] + " " + defaultOrder + ",Id desc");
            }
            else
            {
                source = source.OrderBy(sortStrs[0] + " " + defaultOrder);
            }
            return source;
        }
        catch (Exception)
        {
            return source;
        }
    }
    

    组合一下来个DataList

    public static IQueryable<T> DataList<T>(this IQueryable<T> source, int page = 1, int rows = int.MaxValue, string sort = "Id", string order = "desc")
    {
    	return source.DataSort(sort, order).DataPage(page, rows);
    }
    

    获取单个对象的语句ProDefault

    /// <summary>
    /// 获取一个对象的属性,对象如果为空,则返回属性的默认值
    /// </summary>
    /// <typeparam name="TSource">对象类型</typeparam>
    /// <typeparam name="T">返回值类型</typeparam>
    /// <param name="entity">需要判空的对象</param>
    /// <param name="func">执行函数</param>
    /// <param name="t">默认值</param>
    /// <returns></returns>
    public static T ProDefault<TSource, T>(this TSource entity, Func<TSource, T> func, T t = default(T)) where TSource : class
    {
        if (entity != null)
        {
        	return func(entity);
        }
        return t;
    }
    

    对照文章最开始的例子,用上这些封装后的方法试试。

    list = list.WhereIf(d => d.Name.Contains(query.Name), !string.IsNullOrWhiteSpace(query.Name));
    list = list.WhereIf(d => d.Remark.Contains(query.Remark), !string.IsNullOrWhiteSpace(query.Remark));
    var result = list.DataList(query.PageIndex, query.PageSize).ToList();
    var name = list.FirstOrDefault().ProDefault(d => d.Name, "");
    

    总结

    本文简单介绍一下个人日常开发过程中常用的一些封装方法。那么有没有可能再简单一点,连这些方法都不需要写了呢?只要传入一个Query对象就可以直接得到结果呢?

    答案当然是可以的,这里就简单介绍下思路,具体的实现方式就留着以后再说了~

    通过反射获取查询对象中的数据,拼接查询字符串,借助System.Linq.Dynamic.Core插件的拓展方法,进行数据查询。

    深究其原理,最终还是将查询字符串,处理为相应的表达式树Expression。那么,我们是不是也可以自己来拼接表达式树呢~

    System.Linq.Dynamic.Core地址:https://github.com/zzzprojects/System.Linq.Dynamic.Core

  • 相关阅读:
    可视化理解卷积神经网络
    方差 标准差区别
    SSIS中出现数据流数据源假死状态的解决办法
    IIS中ASP.NET虚拟目录不继承主站点web.config设置的办法(转载)
    SSAS 度量值中的distinct count局聚合方式会数为null的值
    SSAS中CUBE的多对多关系既可以出现在中间事实表上也可以出现在中间维度表上
    SSAS中事实表中的数据如果因为一对多或多对多关系复制了多份,在维度上聚合的时候还是只算一份
    获取当前正在执行的Javascript脚本文件的路径
    C#中try catch中throw ex和throw方式抛出异常有何不同
    SqlServer 一个查询语句导致tempdb增大55G(转载)
  • 原文地址:https://www.cnblogs.com/cplemom/p/14354753.html
Copyright © 2020-2023  润新知