这个组件一年前就写了..文字水平有限,一直没有写出来.现在想来怎么实现的都不记得了。。反正至少是写了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);
}
}
}
}
珂珂的个人博客 - 一个程序猿的个人网站