本项目采用EF作为数据访问框架,根据EF支持lamda表达式的特点扩展出来的查询方法
我相信大家很熟悉下面的代码:
if (user.Name != null) query.Where(x => x.Name == user.Name); if (user.Age != null) query.Where(x => x.Age == user.Age);
判断参数是否为空构造的查询方法,这种方式也是一种很好的查询方法,但是缺点就是太不灵活,如果查询参数一旦很多,这种方式将写一长串,下面我介绍一种利用MVC的特性扩展出来的查询方法。
先来看一段代码:
[FilterAction] public ActionResult ReplyDataList(GridAction filterAction, int newId) { filterAction.filters.Add(new FilterField() { propertyName = "NewId", propertyType = "equal", propertyValue = newId }); var data = _mysqlSearchService.Search<FishReplyEntity>(filterAction).ToList(); var total = _searchService.Count<FishNewsEntity>(filterAction).Count(); Dictionary<string, object> dic = new Dictionary<string, object>(); dic.Add("total", total); dic.Add("rows", data); return Json(dic); }
解释一下,本项目后台使用的EasyUI框架,所以一些固定参数都是根据EasyUI框架来的, FilterAction 是一个属性,集成自MVC的 ActionFilterAttribute属性,看到这里大家应该明白了,就是在访问MVC方法之前干点什么事,来看看FilterAction方法里有什么
public class FilterActionAttribute:ActionFilterAttribute { public FilterActionAttribute() { filterParameterName = "filterAction"; } public string filterParameterName { get; set; } public override void OnActionExecuting(ActionExecutingContext filterContext) { var parameters = filterContext.ActionParameters; bool found = false; if (parameters.ContainsKey(filterParameterName)) found = true; if (found) { GridAction action = new GridAction(); action.pageIndex = filterContext.Controller.ValueOf<int>("page"); action.pageSize = filterContext.Controller.ValueOf<int>("rows"); action.orderName = filterContext.Controller.ValueOf<string>("sort"); action.orderType = filterContext.Controller.ValueOf<string>("order"); action.filters = FilterFactory.Create(filterContext.Controller.ValueOf<string>("filter")); filterContext.ActionParameters[filterParameterName] = action; } base.OnActionExecuting(filterContext); } }
filterParameterName :查询参数名称,用过EasyUI的一看就应该知道page、rows、sort等这些都是EasyUI查询方法需要用的参数,在这方法里用到了两个类FilterFactory和GridAction,
先来看看FilterFactory 类:
public class FilterFactory { public static List<FilterField> Create(string searchFilter) { List<FilterField> list = new List<FilterField>(); if (string.IsNullOrEmpty(searchFilter)) return list; string[] propertys = searchFilter.Split('|'); if (propertys.Length > 0) { foreach (var item in propertys) { string[] fields = item.Split('~'); if (fields.Length != 4) break; if (fields.Length > 0) { //格式Id~equal~1~int|Name~contains~yu~string FilterField filter = new FilterField(); filter.propertyName = fields[0]; filter.propertyType = fields[1]; filter.propertyValue = GetValue(fields[3], fields[2]); // filter.Type = GetType(fields[3]); list.Add(filter); } } } return list; } private static object GetValue(string type,string value) { object obj = null; switch (type) { case "int": int num; int.TryParse(value, out num); obj = num; break; case "string": obj = value; break; case "datetime": DateTime time; DateTime.TryParse(value, out time); obj = time; break; case "bool": bool success; Boolean.TryParse(value, out success); obj = success; break; default: obj = value; break; } return obj; } }
这是一个把查询参数转换为特定的格式,以方便查询使用,再来看看GridAction类:
public class GridAction { public GridAction() { filters = new List<FilterField>(); } public int pageIndex { get; set; } public int pageSize { get; set; } public string orderName { get; set; } public string orderType { get; set; } public List<FilterField> filters { get; set; } /// <summary> /// 多列排序 对应为 key=字段名 value=排序方式 /// </summary> public Dictionary<string, string> dicOrder { get; set; } }
很简单,就是保存一些使用到的参数,在这个类里又出现了个 FilterField类,千万不要认为麻烦,嵌套的类多,这都是必须的,仔细看品味一下代码,就晓得其实还是很好理解的,为了以后方便,现在麻烦点是可以接受的,来看看FilterField类:
public class FilterField { public string propertyName { get; set; } public object propertyValue { get; set; } public string propertyType { get; set; } //查询类型值为:or,and,不填则默认为and public string qureyType{ get; set; } }
这个类就更简单了,就是保存一些值,以便后续需要,到这里查询所传递的参数告一段落。别急到了这里就已经完成一半了,参数格式化了总得有个查询方法吧。
看查询方法代码:
public class MySqlSearchService:IMySqlSearchService { public IQueryable<T> Search<T>(GridAction filterAction) where T : class,new() { if (filterAction == null) throw new ArgumentNullException("filterAction is null"); var repository = DependencyResolver.Current.GetService<IMySqlRepository<T>>(); if (repository == null) throw new ArgumentNullException("repository is null"); //Repository<T> repository = new Repository<T>(); IQueryable<T> query = repository.Query.AsNoTracking(); if (filterAction.filters.Any()) { var filter = filterAction.CommandFunc<T>(); if (filter != null) query = query.Where(filter); } query = query.CommandOrder<T>(filterAction.orderName, filterAction.orderType); if (filterAction.dicOrder != null) { foreach (var item in filterAction.dicOrder) { query = query.CommandThenOrder(item.Key, item.Value); } } int skipNum = (filterAction.pageIndex - 1) * filterAction.pageSize; return query.Skip(skipNum).Take(filterAction.pageSize); } public IQueryable<T> Count<T>(GridAction filterAction) where T : class,new() { if (filterAction == null) throw new ArgumentNullException("filterAction is null"); var repository = DependencyResolver.Current.GetService<IMySqlRepository<T>>(); if (repository == null) throw new ArgumentNullException("repository is null"); IQueryable<T> query = repository.Query.AsNoTracking(); if (filterAction.filters.Any()) { var filter = filterAction.CommandFunc<T>(); if (filter != null) query = query.Where(filter); } return query; } public IQueryable<T> ExtensionSearch<T>(GridAction filterAction) where T : class,new() { if (filterAction == null) throw new ArgumentNullException("filterAction is null"); var repository = DependencyResolver.Current.GetService<IMySqlRepository<T>>(); if (repository == null) throw new ArgumentNullException("repository is null"); IQueryable<T> query = repository.Query.AsNoTracking(); if (filterAction.filters.Any()) { var filter = filterAction.CommandFunc<T>(); if (filter != null) query = query.Where(filter); } query = query.CommandOrder<T>(filterAction.orderName, filterAction.orderType); if (filterAction.dicOrder != null) { foreach (var item in filterAction.dicOrder) { query = query.CommandThenOrder(item.Key, item.Value); } } return query; } }
利用泛型来做到通用,这里就不讲的那么细了,需要对表达式树有一定了解,简单介绍下三个查询方法:
Search<T>(GridAction filterAction) :分页查询返回的数据
Count<T>(GridAction filterAction) : 返回总条数
ExtensionSearch<T>(GridAction filterAction) : 查询所有满足条件的数据
到这里扩展查询方法讲解告一段落,下面放一个实例代码,大家自行研究