LINQ總結

近自己寫個小軟件,琢磨着不用之前那種拼接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寫法:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章