这个组件一年前就写了..文字水平有限,一直没有写出来.现在想来怎么实现的都不记得了。。反正至少是写了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第二个OrderExpressionVisitorasColumn; } 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); } } } }
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第四个WhereExpressionVisitordic, 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)); } } }
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); } } } }