近自己寫個小軟件,琢磨着不用之前那種拼接SQL的三層方法,DAL層想用一下Linq。總結如下:
通常都是GET,POST:
先來一波簡版的:
///查 public List<SYS_User> GetALL() { return entity.SYS_Users.ToList(); } ///增 public int Add(SYS_User f) { entity.SYS_Users.Add(f); return entity.SaveChanges(); } ///改 public int Edit(SYS_User f) { entity.Entry(f).State = EntityState.Modified; return entity.SaveChanges(); } ///刪 public int Delete(int id) { SYS_User f = entity.SYS_Users.Find(id); entity.SYS_Users.Remove(f); return entity.SaveChanges(); }
看到這些,會想到在實際應用中,不是這樣的,光說查詢,就會遇到很多花式的查詢。
然後去百度,去看大神的帖子,可能是我百度的姿勢不對,找到的資料自己總結了一下。
但是還是感覺不是很舒服,可能我對Linq的理解太淺薄了。下面記錄一下:
第一種方法:
/// <summary> /// 第一種linq封裝方法查詢 /// </summary> /// <param name="keywords"></param> /// <returns></returns> public List<SYS_User> Get(params string[] keywords) { var predicate = PredicateBuilder.True<SYS_User>(); foreach (var keyword in keywords) { string temp = keyword; predicate = predicate.And(s => s.User_Name.Contains("1")); } //predicate = predicate.And(s => s.User_Name=="1"); //predicate = predicate.Or(s => s.User_Name=="2"); var result = entity.SYS_Users.Where(predicate).ToList(); return result; }
當然,對應類加個備份吧。
/// <summary> /// 動態查詢 /// 參考URL:https://blog.csdn.net/kongwei521/article/details/27197753 /// </summary> public static class PredicateBuilder { public static Expression<Func<T, bool>> True<T>() { return f => true; } public static Expression<Func<T, bool>> False<T>() { return f => false; } public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge) { // build parameter map (from parameters of second to parameters of first) var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); // replace parameters in the second lambda expression with parameters from the first var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); // apply composition of lambda expression bodies to parameters from the first expression return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters); } public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) { return first.Compose(second, Expression.And); } public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) { return first.Compose(second, Expression.Or); } } public class ParameterRebinder : ExpressionVisitor { private readonly Dictionary<ParameterExpression, ParameterExpression> map; public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) { this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>(); } public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) { return new ParameterRebinder(map).Visit(exp); } protected override Expression VisitParameter(ParameterExpression p) { ParameterExpression replacement; if (map.TryGetValue(p, out replacement)) { p = replacement; } return base.VisitParameter(p); } }
第二種方法:
/// <summary> /// 第二種linq封裝方法動態查詢 /// </summary> public void GetDong() { #region 試水 var query = SpecificationBuilder.Create<SYS_User>(); query = query.Equals(d => d.User_Name, "1"); query = query.Equals(d => d.Phone, "1"); var result = entity.SYS_Users.Where(query.Predicate).ToList(); #endregion #region 執行Json動態查詢 //{a => (((a.User_Name == "1") And (a.Phone == "1")) Or (a.Phone == "ccccc"))} string queryJson = "{\"[EQUAL][And]User_Name\":\"1\",\"[EQUAL][And]Phone\":\"1,ccccc\"}"; if (!string.IsNullOrEmpty(queryJson)) { var predicate = Utils.GetSerchExtensions<SYS_User>(queryJson); var result1 = entity.SYS_Users.Where(predicate).ToList(); //query.Predicate = query.Predicate.And(predicate); } #endregion #region 組合單個查詢條件 QueryEntity queryEntity = new QueryEntity() { LogicOperation = LogicOperation.EQUAL, PredicateType = PredicateType.AND, Column = "User_Name", Value = "1" }; var qqqqq = Utils.GetSerchExtensions<SYS_User>(new List<QueryEntity>() { queryEntity }); var a = entity.SYS_Users.Where(qqqqq).ToList(); #endregion #region 組合多個查詢條件 List<QueryEntity> queryEntities = new List<QueryEntity>(); queryEntities.Add(new QueryEntity { LogicOperation = LogicOperation.EQUAL, PredicateType = PredicateType.AND, Column = "User_Name", Value = "1" }); queryEntities.Add(new QueryEntity { LogicOperation = LogicOperation.EQUAL, PredicateType = PredicateType.AND, Column = "Phone", Value = "1" }); qqqqq = Utils.GetSerchExtensions<SYS_User>(queryEntities); a = entity.SYS_Users.Where(qqqqq).ToList(); #endregion }
缺的方法在這:
/// <summary> /// 手動去拼接動態表達式 /// </summary> /// <typeparam name="T"></typeparam> public class ExpressionHandle<T> where T : class { public Expression PrepareConditionLambda(IList<ParamObject> paramList, ParameterExpression paramExp) { List<Expression> expList; if (null == paramList) { expList = new List<Expression>(1); var valueEqual = Expression.Constant(1); var expEqual = Expression.Equal(valueEqual, valueEqual); expList.Add(expEqual); } else { expList = new List<Expression>(paramList.Count); #region 篩選條件 foreach (var p in paramList) { var exp = Expression.Property(paramExp, p.Name); var propertyType = typeof(T).GetProperty(p.Name).PropertyType; //得到此字段的數據類型 var value = propertyType == typeof(Guid?) ? new Guid(p.Value.ToString()) : Convert.ChangeType(p.Value, TypeHelper.GetUnNullableType(propertyType)); switch (p.Operation) { case LogicOperation.LIKE: var containsMethod = typeof(string).GetMethod("Contains"); var valueLike = Expression.Constant(value, propertyType); var expLike = Expression.Call(exp, containsMethod, valueLike); expList.Add(expLike); break; case LogicOperation.EQUAL: var valueEqual = Expression.Constant(value, propertyType); //值 var expEqual = Expression.Equal(exp, valueEqual); //拼接成 t=>t.name=valueEqual expList.Add(expEqual); break; case LogicOperation.LT: var valueLT = Expression.Constant(value, propertyType); //值 var expLT = Expression.LessThan(exp, valueLT); //拼接成 t=>t.name<valueEqual expList.Add(expLT); break; case LogicOperation.GT: var valueGT = Expression.Constant(value, propertyType); var expGT = Expression.GreaterThan(exp, valueGT); expList.Add(expGT); break; case LogicOperation.NOTEQUAL: var valuent = Expression.Constant(value, propertyType); var expnt = Expression.NotEqual(exp, valuent); expList.Add(expnt); break; //case LogicOperation.CONTAINS: // //var valueCT = Expression.Constant(value, propertyType); // var type = typeof(string); // var expCT = Expression.Constant(exp, type); // expList.Add(expCT); // break; } } #endregion } return expList.Aggregate<Expression, Expression>(null, (current, item) => current == null ? item : Expression.And(current, item)); } } /// <summary> /// /// </summary> public class QueryModel { IList<ParamObject> _items = new List<ParamObject>(); public IList<ParamObject> Items { get { return _items; } set { _items = value; } } } /// <summary> /// 參數 /// </summary> public class ParamObject { public string Name { get; set; } public LogicOperation Operation { get; set; } public object Value { get; set; } } /// <summary> /// 排序 /// </summary> public class SortObject { public string OrderBy { get; set; } public SortOperation Sort { get; set; } } /// <summary> /// 排序方式 /// </summary> public enum SortOperation { ASC, DESC } /// <summary> /// 查詢方式 /// </summary> public enum LogicOperation { LIKE, //包含,模糊查詢 EQUAL, //等於 LT, //小於 GT, //大於 CONTAINS, //包含,In查詢 NOTEQUAL //不等於 } /// <summary> /// /// </summary> public static class TypeHelper { public static Type GetUnNullableType(Type conversionType) { if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition() == typeof(Nullable<>)) { //如果是泛型方法,且泛型類型爲Nullable<>則視爲可空類型 //並使用NullableConverter轉換器進行轉換 var nullableConverter = new System.ComponentModel.NullableConverter(conversionType); conversionType = nullableConverter.UnderlyingType; } return conversionType; } } /// <summary> /// 連接方式 /// </summary> public enum PredicateType { AND, OR } /// <summary> /// 查詢方式 /// </summary> public enum SearchType { Between, Like, Equals } /// <summary> /// 查詢實體 /// </summary> public class QueryEntity { /// <summary> /// 查詢方式 /// </summary> public LogicOperation LogicOperation { get; set; } /// <summary> /// 連接方式 /// </summary> public PredicateType PredicateType { get; set; } /// <summary> /// 列名 /// </summary> public string Column { get; set; } /// <summary> /// 列值 /// </summary> public object Value { get; set; } } }
public class Utils { #region 把查詢條件拼接爲Extensions /// <summary> /// 把查詢條件拼接爲Extensions /// </summary> /// <typeparam name="TEntity">查詢實體</typeparam> /// <param name="searchJson">查詢條件,例如:[like][or]name:123</param> /// <returns></returns> public static Expression<Func<TEntity, bool>> GetSerchExtensions<TEntity>(String searchJson) where TEntity : class, new() { try { var ja = (JArray)JsonConvert.DeserializeObject("[" + searchJson + "]"); //把查詢條件轉換爲Json格式 var enumerableQuery = new EnumerableQuery<KeyValuePair<string, JToken>>(ja[0] as JObject); return GetSerchExtensions<TEntity>(enumerableQuery); //把查詢條件拼接爲Extensions } catch (Exception) { throw; } } /// <summary> /// 把查詢條件拼接爲Extensions /// </summary> /// <typeparam name="TEntity">查詢實體</typeparam> /// <param name="enumerableQuery">查詢條件</param> /// <returns></returns> public static Expression<Func<TEntity, bool>> GetSerchExtensions<TEntity>(EnumerableQuery<KeyValuePair<string, JToken>> enumerableQuery) where TEntity : class, new() { var paramExp = Expression.Parameter(typeof(TEntity), "a"); if (null == enumerableQuery || !enumerableQuery.Any()) { var valueEqual = Expression.Constant(1); var expEqual = Expression.Equal(valueEqual, valueEqual); return Expression.Lambda<Func<TEntity, bool>>(expEqual, paramExp); //如果參數爲空,返回一個a=>1=1 的值 } var modeltypt = typeof(TEntity); //實體類型 var keyList = enumerableQuery.Select(e => e.Key).ToList(); //取出Json 的每個字符串 Expression whereExp = null; keyList.ForEach(s => { var searchTypeStr = s.Substring(1, s.LastIndexOf("][", StringComparison.Ordinal) - 1); //查詢方式 Like var ab = s.Substring(s.LastIndexOf("][", StringComparison.Ordinal) + 2); var joinTypeStr = ab.Remove(ab.LastIndexOf("]", StringComparison.Ordinal)); //連接方式 or var searchField = s.Substring(s.LastIndexOf("]", StringComparison.Ordinal) + 1); //查詢的列名 name var value = enumerableQuery.FirstOrDefault(v => v.Key == s).Value.ToString(); //值 123 LogicOperation searchType; //查詢方式 PredicateType joinType; //連接方式 if (Enum.TryParse(searchTypeStr.ToUpper(), out searchType) && Enum.TryParse(joinTypeStr.ToUpper(), out joinType) && modeltypt.GetProperties().Any(p => String.Equals(p.Name, searchField, StringComparison.CurrentCultureIgnoreCase))) //這個實體有這個列名 { var firstOrDefault = modeltypt.GetProperties().FirstOrDefault(p => String.Equals(p.Name, searchField, StringComparison.CurrentCultureIgnoreCase)); if (firstOrDefault == null) return; var selCol = firstOrDefault.Name; //查詢的列名 var splitList = value.Split(',').ToList(); //這個位置是的處理是默認認爲當查詢值中包含,的視爲或者的查詢:例如 A='abc,def' 處理成 (A='def' OR A='abc'),但是時間上這塊無法滿足就要查詢包含,的數據的求 for (var i = 0; i < splitList.Count; i++) { var val = splitList[i]; if (val == null || string.IsNullOrWhiteSpace(val)) continue; var expressionFuncEquals = PrepareConditionLambda<TEntity>(selCol, val, paramExp, searchType); //得到這個查詢的表達式 whereExp = i != 0 ? (whereExp == null ? expressionFuncEquals : Expression.Or(whereExp, expressionFuncEquals)) : (joinType == PredicateType.OR ? (whereExp == null ? expressionFuncEquals : Expression.Or(whereExp, expressionFuncEquals)) : (whereExp == null ? expressionFuncEquals : Expression.And(whereExp, expressionFuncEquals))); } } }); return Expression.Lambda<Func<TEntity, bool>>(whereExp, paramExp); ; } /// <summary> /// 把查詢條件拼接爲Extensions /// </summary> /// <typeparam name="TEntity">實體類</typeparam> /// <param name="queryEntitys">查詢實體</param> /// <returns></returns> public static Expression<Func<TEntity, bool>> GetSerchExtensions<TEntity>(List<QueryEntity> queryEntitys) where TEntity : class, new() { var paramExp = Expression.Parameter(typeof(TEntity), "a"); if (null == queryEntitys || !queryEntitys.Any()) { var valueEqual = Expression.Constant(1); var expEqual = Expression.Equal(valueEqual, valueEqual); return Expression.Lambda<Func<TEntity, bool>>(expEqual, paramExp); //如果參數爲空,返回一個a=>1=1 的值 } var modeltypt = typeof(TEntity); //實體類型 Expression whereExp = null; queryEntitys.ForEach(q => { LogicOperation searchType = q.LogicOperation; //查詢方式 PredicateType joinType = q.PredicateType; //連接方式 var searchField = q.Column; //查詢的列名 name var value = q.Value; //值 123 if (modeltypt.GetProperties().Any(p => String.Equals(p.Name, searchField, StringComparison.CurrentCultureIgnoreCase))) //這個實體有這個列名 { var firstOrDefault = modeltypt.GetProperties().FirstOrDefault(p => String.Equals(p.Name, searchField, StringComparison.CurrentCultureIgnoreCase)); if (firstOrDefault == null) return; var selCol = firstOrDefault.Name; //查詢的列名 var splitList = value.ToString().Split(',').ToList(); //這個位置是的處理是默認認爲當查詢值中包含,的視爲或者的查詢:例如 A='abc,def' 處理成 (A='def' OR A='abc'),但是時間上這塊無法滿足就要查詢包含,的數據的求 for (var i = 0; i < splitList.Count; i++) { if (splitList[i] == null || string.IsNullOrWhiteSpace(splitList[i])) continue; var expressionFuncEquals = PrepareConditionLambda<TEntity>(selCol, splitList[i], paramExp, searchType); //得到這個查詢的表達式 whereExp = i != 0 ? (whereExp == null ? expressionFuncEquals : Expression.Or(whereExp, expressionFuncEquals)) : (joinType == PredicateType.OR ? (whereExp == null ? expressionFuncEquals : Expression.Or(whereExp, expressionFuncEquals)) : (whereExp == null ? expressionFuncEquals : Expression.And(whereExp, expressionFuncEquals))); } } }); return Expression.Lambda<Func<TEntity, bool>>(whereExp, paramExp); ; } /// <summary> /// 得到字段查詢的表達式 /// </summary> /// <typeparam name="TEntity">實體</typeparam> /// <param name="name">查詢列名</param> /// <param name="dateValue">數據值</param> /// <param name="paramExp">參數</param> /// <param name="searchType">查詢方式(默認是等於查詢)</param> /// <returns></returns> private static Expression PrepareConditionLambda<TEntity>(string name, object dateValue, ParameterExpression paramExp, LogicOperation searchType = LogicOperation.EQUAL) { if (dateValue == null) throw new ArgumentNullException("dateValue"); if (paramExp == null) throw new ArgumentNullException("paramExp"); var exp = Expression.Property(paramExp, name); var propertyType = typeof(TEntity).GetProperty(name).PropertyType; //得到此字段的數據類型 object value; //propertyType == typeof(Guid?) ? new Guid(dateValue.ToString()) : Convert.ChangeType(dateValue, TypeHelper.GetUnNullableType(propertyType)); if (propertyType == typeof(Guid?) || propertyType == typeof(Guid)) { value = new Guid(dateValue.ToString()); } else { value = Convert.ChangeType(dateValue, TypeHelper.GetUnNullableType(propertyType)); } Expression expEqual = null; switch (searchType) { case LogicOperation.EQUAL: //等於查詢 var valueEqual = Expression.Constant(value, propertyType); //值 expEqual = Expression.Equal(exp, valueEqual); //拼接成 t=>t.name=valueEqual break; case LogicOperation.LIKE: //模糊查詢 var containsMethod = typeof(string).GetMethod("Contains"); var valueLike = Expression.Constant(value, propertyType); expEqual = Expression.Call(exp, containsMethod, valueLike); break; } return expEqual; } #endregion }
類似Format寫法: