珂珂的个人博客 - 一个程序猿的个人网站

自己来实现linq查询(一)

自己来实现linq查询(一)

自己来实现linq查询(二)

自己来实现linq查询(三)

这个组件一年前就写了..文字水平有限,一直没有写出来.现在想来怎么实现的都不记得了。。反正至少是写了2个差不多通宵,兴趣来了挡也挡不住呀.其中有一个方法没百度到,还是谷歌去搜的英文对着词典看的....

虽然有微软有LINQ 不过只支持SqlServer ,EF 的话 对多数据库也不是支持太好,有好多字段类型不同数据库会不同。网上也有LINQ TO MySQL  之类的,本着学习的态度,我决定来自己实现一个LINQ。不求太复杂,只需要简单的单表查询,毕竟没那么大精力去研究。

真的不知道该如何下笔了。。实在忘了,以后有点东西还是马上分享吧。对于查询,好像是继承ExpressionVisitor这个类

第一个ColumnExpressionVisitor类


using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace FYJ.Data.Linq
{

    internal class ColumnProjection
    {
        internal string Columns;
        internal Expression Selector;
        public Dictionary asColumn;
    }

    internal class ColumnExpressionVisitor : ExpressionVisitor
    {
        public ColumnExpressionVisitor()
        {
            if (miGetValue == null)
            {
                miGetValue = typeof(ProjectionRow).GetMethod("GetValue");
            }
        }

        StringBuilder sb = new StringBuilder();
        ListcolumnList = new List();
        ListcolumnAsList = new List();
        static MethodInfo miGetValue;
        ParameterExpression row;
        int iColumn;

        internal ColumnProjection Translate(Expression expression, ParameterExpression row)
        {
            //解析 Expression> selector
            //ListcolumnList = new List();
            //ListcolumnAsList = new List();
            //if (selector.Body is NewExpression)
            //{
            //    foreach (var v in ((NewExpression)selector.Body).Members)
            //    {
            //        columnAsList.Add(v.Name);
            //    }

            //    foreach (var v in ((NewExpression)selector.Body).Arguments)
            //    {
            //        columnList.Add((v as System.Linq.Expressions.MemberExpression).Member.Name);
            //    }
            //}

            this.row = row;
            Expression selector = this.Visit(expression);
            if ((expression as System.Linq.Expressions.NewExpression) != null)
            {
                var asMembers = (expression as System.Linq.Expressions.NewExpression).Members;
                foreach (var v in asMembers)
                {
                    columnAsList.Add(v.Name);
                }
            }

            Dictionary asColumnDic = new Dictionary();
            if (columnList.Count == columnAsList.Count) //如果别名与实际列名数相同 返回别名
            {
                for (int i = 0; i < columnList.Count; i++) { if (columnList[i] == columnAsList[i]) //如果别名与实际列名相同 { sb.Append(columnList[i] + ","); } else { asColumnDic.Add(columnList[i],columnAsList[i]); sb.Append(columnList[i] + " " + columnAsList[i] + ","); } } } else { for (int i = 0; i < columnList.Count; i++) { sb.Append(columnList[i] + ","); } } return new ColumnProjection { Columns = sb.ToString().TrimEnd(','), Selector = selector,asColumn=asColumnDic }; } protected override Expression VisitMember(MemberExpression m) { if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter) { columnList.Add(m.Member.Name); return Expression.Convert(Expression.Call(this.row, miGetValue, Expression.Constant(iColumn++)), m.Type); } else { return base.VisitMember(m); } } } } 
第二个OrderExpressionVisitor


using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace FYJ.Data.Linq
{
   internal class OrderExpressionVisitor : ExpressionVisitor
    {
        StringBuilder sb = new StringBuilder();
        ListorderList = new List();
        private string afterOrderby;
        internal OrderExpressionVisitor(string afterOrderby)
        {
            this.afterOrderby = afterOrderby;
        }

      
        internal string Translate(Expression expression)
        {
            this.Visit(expression);
            if (orderList.Count == 0)
            {
                return "";
            }

            sb.Append(" ORDER BY ");
            foreach (string s in orderList)
            {
                sb.Append(s + " " + afterOrderby + ",");
            }
            return sb.ToString().TrimEnd(',')+" ";
        }


        protected override Expression VisitMember(MemberExpression m)
        {

            if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter)
            {
                orderList.Add(m.Member.Name);
                return m;
            }
            else
            {
                return base.VisitMember(m);
            }
        }
    }
}
第三个QueryExpressionVisitor



using FYJ.Data.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace FYJ.Data.Linq
{
    

    public abstract class ProjectionRow
    {
        public abstract object GetValue(int index);
    }


    public class QueryExpressionVisitor : ExpressionVisitor
    {
        private FYJ.Data.IDbHelper db;
        private string tableName, where, order;
        private int skip, take;
        private ColumnProjection projection;
        private ParameterExpression row;

        internal QueryExpressionVisitor(Type elementType, FYJ.Data.IDbHelper db = null)
        {
            #region 获取表名 
            object[] objs = elementType.GetCustomAttributes(typeof(TableAttribute), false);
            if (objs.Length <= 0 || db == null) { tableName = elementType.Name; } else { TableAttribute tableAttribute = (TableAttribute)objs[0]; if (tableAttribute.IsGetTbPre) //如果要获取表名前缀 { tableName = tableAttribute.Name; } } #endregion this.db = db; } private string ReplaceOrder(Dictionary dic, string order)
        {
            if (dic != null&&dic.Count>0)
            {
                foreach (string s in dic.Keys)
                {
                    order = order.Replace(s,dic[s]);
                }
            }

            return order;
        }
        internal TranslateResult Translate(Expression expression)
        {
            StringBuilder sb = new StringBuilder();
            this.row = Expression.Parameter(typeof(ProjectionRow), "row");
            this.Visit(expression);
            string column = projection==null?"":projection.Columns;
            if (db != null)
            {
                if (take > 0)
                {
                    if ((db.DbHelperTypeEnum == DbHelperType.SqlServer)
                       || (db.DbHelperTypeEnum == DbHelperType.OleDb))
                    {
                        tableName = "ztku_tb_story";
                        sb.AppendLine("SELECT * FROM");
                        sb.AppendLine("(");
                        sb.AppendLine("SELECT row_number() " + (String.IsNullOrEmpty(order) ? "" : ("over(" + order + ")")) + " AS rownum," + (String.IsNullOrEmpty(column) ? "*" : column) + " FROM " + tableName + " " + where);
                        sb.AppendLine(") AS table1 ");
                        sb.AppendLine(" WHERE (rownum  BETWEEN " + (skip + 1) + " AND " + (skip + take) + " )" +(projection==null?order: ReplaceOrder(projection.asColumn, order)));
                    }

                    if ((db.DbHelperTypeEnum == DbHelperType.MySql)
                      || (db.DbHelperTypeEnum == DbHelperType.SqlLite))
                    {
                        sb.AppendLine( "SELECT " + (String.IsNullOrEmpty(column) ? "*" : column) + " FROM " + tableName + " " + where + " " + order+" limit "+skip+","+take);
                    }

                    if (db.DbHelperTypeEnum == DbHelperType.Oracle)
                    {
                        sb.AppendLine("SELECT * FROM");
                        sb.AppendLine("(");
                        sb.AppendLine("SELECT ROWNUM  rownum," + (String.IsNullOrEmpty(column) ? "*" : column) + " FROM " + tableName + " "+ where);
                        sb.AppendLine(") table1 ");
                        sb.AppendLine(" WHERE (rownum  BETWEEN " + (skip + 1) + " AND " + (skip + take) + " )" + (projection == null ? order : ReplaceOrder(projection.asColumn, order)));
                    }
                }
            }

            string str = ((sb.Length == 0) ? ("SELECT " + (String.IsNullOrEmpty(column) ? "*" : column) + " FROM " + tableName + " " + where + " " + order) : sb.ToString());

            return new TranslateResult
            {
                CommandText = str,
                Prsojector = this.projection != null ? Expression.Lambda(this.projection.Selector, this.row) : null
            };
        }

        private static Expression StripQuotes(Expression e)
        {
            while (e.NodeType == ExpressionType.Quote)
            {
                e = ((UnaryExpression)e).Operand;
            }
            return e;
        }

        private string GetAfterOrderBy(string methodName)
        {
            switch (methodName)
            {
                case "OrderBy":
                case "ThenBy":
                    return "ASC";
                case "OrderByDescending":
                case "ThenByDescending":
                    return "DESC";
                default:
                    return "";
            }
        }

        protected override Expression VisitMethodCall(MethodCallExpression m)
        {

            if (m.Method.DeclaringType == typeof(Queryable))
            {
                if (m.Method.Name == "Take")
                {
                    var v = m.Arguments[1] as System.Linq.Expressions.ConstantExpression;
                    if (v != null)
                    {
                        take = Convert.ToInt32(v.Value);
                    }
                    this.Visit(m.Arguments[0]);
                    return m;
                }

                if (m.Method.Name == "Skip")
                {
                    var v = m.Arguments[1] as System.Linq.Expressions.ConstantExpression;
                    if (v != null)
                    {
                        skip = Convert.ToInt32(v.Value);
                    }
                    this.Visit(m.Arguments[0]);
                    return m;
                }

                LambdaExpression lambda = (LambdaExpression)StripQuotes(m.Arguments[1]);
                switch (m.Method.Name)
                {
                    case "Where":
                        where = new WhereExpressionVisitor().Translate(lambda.Body);
                        this.Visit(m.Arguments[0]);
                        return m;
                    case "Select":

                         projection = new ColumnExpressionVisitor().Translate(lambda.Body, this.row);

                        this.Visit(m.Arguments[0]);
                        return m;
                    case "OrderBy":
                    case "OrderByDescending":
                    case "ThenBy":
                    case "ThenByDescending":
                        order = new OrderExpressionVisitor(GetAfterOrderBy(m.Method.Name)).Translate(lambda.Body);
                        this.Visit(m.Arguments[0]);
                        return m;
                }

            }
            throw new NotSupportedException(string.Format("The method '{0}' is not supported", m.Method.Name));
        }

    }
}
第四个WhereExpressionVisitor



using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace FYJ.Data.Linq
{
    internal class WhereExpressionVisitor : ExpressionVisitor
    {
        private StringBuilder sb=new StringBuilder();
        internal string Translate(Expression expression)
        {
            this.Visit(expression);
            if (sb.Length ==0)
            {
                return " WHERE 1=1 ";
            }
            return " WHERE "+sb.ToString();
        }

        protected override Expression VisitUnary(UnaryExpression u)
        {
            switch (u.NodeType)
            {
                case ExpressionType.Not:
                    sb.Append(" NOT ");
                    this.Visit(u.Operand);
                    break;
                default:
                    this.Visit(u.Operand);
                    break;
            }

            return u;
        }

        protected override Expression VisitBinary(BinaryExpression b)
        {
            sb.Append("(");
            this.Visit(b.Left);
            switch (b.NodeType)
            {
                case ExpressionType.AndAlso:
                    sb.Append(" AND ");
                    break;
                case ExpressionType.OrElse:
                    sb.Append(" OR");
                    break;
                case ExpressionType.Equal:
                    sb.Append(" = ");
                    break;
                case ExpressionType.NotEqual:
                    sb.Append(" <> ");
                    break;
                case ExpressionType.LessThan:
                    sb.Append(" < "); break; case ExpressionType.LessThanOrEqual: sb.Append(" <= "); break; case ExpressionType.GreaterThan: sb.Append(" > ");
                    break;
                case ExpressionType.GreaterThanOrEqual:
                    sb.Append(" >= ");
                    break;
                    //另外加的
                case ExpressionType.Constant:
                    sb.Append(" LIKE ");
                    break;
                default:
                    throw new NotSupportedException(string.Format("The binary operator '{0}' is not supported", b.NodeType));
            }

            this.Visit(b.Right);
            sb.Append(")");

            return b;
        }

        protected override Expression VisitConstant(ConstantExpression c)
        {
            IQueryable q = c.Value as IQueryable;
            if (q != null)
            {
                sb.Append(q.ElementType.Name);
            }

            else if (c.Value == null)
            {

                sb.Append("NULL");

            }

            else
            {

                switch (Type.GetTypeCode(c.Value.GetType()))
                {

                    case TypeCode.Boolean:

                        sb.Append(((bool)c.Value) ? 1 : 0);

                        break;

                    case TypeCode.String:
                        sb.Append("'");
                        sb.Append(c.Value);
                        sb.Append("'");
                        break;

                    case TypeCode.Object:
                        if (q == null)
                        {
                            
                            object o = c.Type.GetFields()[0].GetValue(c.Value);
                            sb.Append("'");
                            sb.Append(o);
                            sb.Append("'");
                        }
                    
                        break;
                       // throw new NotSupportedException(string.Format("The constant for '{0}' is not supported", c.Value));

                    default:

                        sb.Append(c.Value);

                        break;

                }

            }

            return c;

        }

        protected override Expression VisitMember(MemberExpression m)
        {

            if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter)
            {
                sb.Append(m.Member.Name);
                return m;
            }
            else
            {
                return base.VisitMember(m);
            }
        }
    }
}



上一篇:URL 签名验证

下一篇:个人代码全部开源


0 评论

查看所有评论

给个评论吧