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

posted @ 2021-02-03 14:57  傅小灰  阅读(1899)  评论(0编辑  收藏  举报