基于快速反射的小框架

我是一个很懒的程序员,第一次写,不知道从什么说起,就从数据库表开始吧!

新建一个UserInfo表:

接着我们要开始写代码对UserInfo做增删改查:

第一步我们要首先要生成一个Model类,代码生成器很多,这里我们用一个sql完成:(有点长,当然这样生成出来再贴还是很麻烦,后面我用这样的sql去查所有表,然后用Emit方式去

反射出所有表的Model类,然后把那个Assembly直接保存成dll文件,直接引用这个dll即可)

--通过sql生成model类代码
declare @tablename nvarchar(100)
set @tablename='UserInfo'


DECLARE @r varchar(8000)
SET @r = ''
select
@r = @r + CHAR(13) +
(CASE
WHEN pk.is_primary_key = 1 THEN ' [Description("IsPrimaryKey")]' + CHAR(13)
WHEN pk.is_primary_key is null THEN ''
END)+
' public '+
(CASE
WHEN Type.name = 'uniqueidentifier' THEN 'Guid'
WHEN Type.name = 'nvarchar' THEN 'string'
WHEN Type.name = 'xml' THEN 'string'
WHEN Type.name = 'char' THEN 'string'
WHEN Type.name = 'varchar' THEN 'string'
WHEN Type.name = 'text' THEN 'byte[]'
WHEN Type.name = 'ntext' THEN 'byte[]'
WHEN Type.name = 'image' THEN 'byte[]'
WHEN Type.name = 'varbinary' THEN 'byte[]'
WHEN Type.name = 'tinyint' THEN 'Int8'
WHEN Type.name = 'int' THEN 'int'
WHEN Type.name = 'smallint' THEN 'short'
WHEN Type.name = 'bigint' THEN 'long'
WHEN Type.name = 'float' THEN 'float'
WHEN Type.name = 'money' THEN 'decimal'
WHEN Type.name = 'decimal' THEN 'decimal'
WHEN Type.name = 'numeric' THEN 'decimal'
WHEN Type.name = 'datetime' THEN 'DateTime'
WHEN Type.name = 'bit' THEN 'bool'
ELSE Type.name
END) +
' '+STUFF(Col.Name,1,1,UPPER(SUBSTRING(Col.Name,1,1)))
+'{ get; set; }'
from sys.objects Tab inner join sys.columns Col on Tab.object_id =Col.object_id
inner join sys.types Type on Col.system_type_id = Type.system_type_id
left join sys.identity_columns identity_columns on Tab.object_id = identity_columns.object_id and Col.column_id = identity_columns.column_id
left join(
select index_columns.object_id,index_columns.column_id,indexes.is_primary_key
from sys.indexes indexes inner join sys.index_columns index_columns
on indexes.object_id = index_columns.object_id and indexes.index_id = index_columns.index_id
where indexes.is_primary_key = 1
) PK on Tab.object_id = PK.object_id AND Col.column_id = PK.column_id
where Type.Name <> 'sysname' and Tab.type = 'U' and Tab.Name<>'sysdiagrams' and Tab.Name=@tablename
set @r=STUFF(@r, 1, 1, '')
select
'using System;'+Char(13)+
'using System.ComponentModel;'+Char(13)+Char(13)+
'namespace Business'+Char(13)+
'{'+Char(13)+
' public class '+@tablename+Char(13)+
' {'+Char(13)+
@r+Char(13)+
' }'+Char(13)+
'}'+Char(13)

执行完上面的sql,我们把结果复制出来,添加项目里保存成Userinfo.cs

ContractedBlock.gif ExpandedBlockStart.gif View Code
using System;
using System.ComponentModel;

namespace Business
{
public class UserInfo
{
[Description("IsPrimaryKey")]
public Guid Id { get; set; }
public DateTime RegDate { get; set; }
public bool IsVip { get; set; }
public string UserName { get; set; }
public string UserPass { get; set; }
public string Email { get; set; }
}
}

我们把所有的主键都加上属性标签[Description("IsPrimaryKey")],如果我们的表是联合主键,就是多几个属性标签,这些标签是为了我们以后拼sql语句知道谁是主键用的。

Model类做好了,我们就可以引入我们的核心库Core,对数据进行增删改了。
这里先不看我们的Core里写了些什么直接看怎么用。

不用生成什么逻辑层代码,直接就可以这么用。

如果您感兴趣这些是怎么做到的,我们就来看看Core里都有些什么东西。

这些代码基本都是抄来的,我只是改改名字,亲要是觉得有用,亲也可以抄一抄。

我就来简单介绍一下:

Comb伪Guid,这个很多文章都介绍过的,用时间二进制替换Guid生成出有序的Guid,我觉得做主键挺好用的。

DBConnstring什么都没有,只有一个属性做连接串初始化。

Extensions里面是放了一些我喜欢的,和常用的扩展方法,大部分都是大牛们写的,我改改名字。

值得一提的是 public static T ParseTo<T>(this IConvertible convertibleValue) 这个是转类型最好用的,剩下的都在源代码里,亲们应该都看过的。对了Core里大部分的类命名空间我都用的System,我说过我很懒,能少写一个using就少写一个using~~~

SqlExecuter是ado.net数据库访问类,用了三四年的还是觉得拼sql最习惯(没用Prepare语句那种的,习惯问题),不是说那些LinqToSql EF Nhibernate NSpring不好,主要是太麻烦了,生成来,生成去,拷过来拷过去的,看着一堆堆的文件夹,一堆堆的文件,就发憷,不管亲们觉得怎么样,反正我是不想用了。

Logic.Emit和Logic.Expression是最核心的部分,也是抄的最多的部分,这里我们详细介绍。

Logic.Expression:(主要依据园子里的大牛们的文章和代码)

说说查询,利用传入的泛型,一般的就是我们生成的model类,也就是DTO对象类,类名即为表名,属性名即为表字段名,拼一条查询语句出来:

ContractedBlock.gif ExpandedBlockStart.gif View Code
public static List<T> GetAll<T>(Expression<Func<T, bool>> func) where T : new()
{
List<T> list = new List<T>();
string where = string.Empty;
if (func.Body is BinaryExpression)
{
BinaryExpression be = ((BinaryExpression)func.Body);
where = "where " + BinarExpressionProvider(be.Left, be.Right, be.NodeType);
}
string sql = "select {0} from [{1}] {2}".FormatWith(string.Join(",", GetFields<T>().ToArray()), GetTableName<T>(), where);
foreach (DataRow dr in exec.QueryTable(sql).Rows)
{
list.Add(dr.GetModelByDataRow<T>());
}
return list;
}

这个方法把查询结果DataRow转化成对象:

ContractedBlock.gif ExpandedBlockStart.gif View Code
public static T GetModelByDataRow<T>(this DataRow data) where T : new()
{
T t = new T();
PropertyInfo[] properties = typeof(T).GetProperties();
foreach (PropertyInfo p in properties)
{
object value = data[p.Name] == DBNull.Value ? null : data[p.Name];
p.FastSetValue<T>(t, value);
}
return t;
}

这里面用到的FastSetValue就是Expression表达式快速反射的东西。

ContractedBlock.gif ExpandedBlockStart.gif View Code
static void FastSetValue<T>(this PropertyInfo property, T t, object value)
{
MethodInfo m = property.GetSetMethod();
GetSetDelegate<T>(m, property.PropertyType)(t, m, value);
}
ContractedBlock.gif ExpandedBlockStart.gif View Code
        static Func<T, MethodInfo, object, object> GetSetDelegate<T>(MethodInfo m, Type type)
{
var param_obj = Expression.Parameter(typeof(T), "obj");
var param_val = Expression.Parameter(typeof(object), "val");
var param_m = Expression.Parameter(typeof(MethodInfo), "m");
var body_val = Expression.Convert(param_val, type);
var body = Expression.Call(param_obj, m, body_val);
Action<T, MethodInfo, object> set = Expression.Lambda<Action<T, MethodInfo, object>>(body, param_obj, param_m, param_val).Compile();
return (instance, method, v) =>
{
set(instance, method, v);
return null;
};
}

因为用linqtosql的时候就觉得用lambda表达式做查询条件很方便。所以就找啊找,找到了解析lambda变where语句的文章,抄过来也就是:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 // 条件表达式解析。
static string BinarExpressionProvider(Expression left, Expression right, ExpressionType type)
{
string sb = "(";
//先处理左边
string tmpStr = ExpressionRouter(left);
if (tmpStr == "null")
{
Expression temp = left;
left = right;
right = temp;
}
sb += ExpressionRouter(left);
sb += ExpressionTypeCast(type);
//再处理右边
tmpStr = ExpressionRouter(right);
if (tmpStr == "null")
{
if (sb.EndsWith(" ="))
sb = sb.Substring(0, sb.Length - 2) + " is null";
else if (sb.EndsWith("<>"))
sb = sb.Substring(0, sb.Length - 2) + " is not null";
}
else
sb += tmpStr;
return sb += ")";
}
// 表达式路由。
static string ExpressionRouter(Expression exp)
{
string sb = string.Empty;
if (exp is BinaryExpression)
{
BinaryExpression be = ((BinaryExpression)exp);
return BinarExpressionProvider(be.Left, be.Right, be.NodeType);
}
else if (exp is MemberExpression)
{
if (!exp.ToString().StartsWith("value("))
{
MemberExpression me = ((MemberExpression)exp);
return me.Member.Name;
}
else
{
var result = Expression.Lambda(exp).Compile().DynamicInvoke();
if (result == null)
return "null";
if (result is ValueType)
return result.ToString();
else if (result is string || result is DateTime || result is char)
return string.Format("'{0}'", (result as string).Replace("'", "''"));
}
}
else if (exp is NewArrayExpression)
{
NewArrayExpression ae = ((NewArrayExpression)exp);
StringBuilder tmpstr = new StringBuilder();
foreach (Expression ex in ae.Expressions)
{
tmpstr.Append(ExpressionRouter(ex));
tmpstr.Append(",");
}
return tmpstr.ToString(0, tmpstr.Length - 1);
}
else if (exp is MethodCallExpression)
{
MethodCallExpression mce = (MethodCallExpression)exp;
if (mce.Method.Name == "Like")
return string.Format("({0} like {1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
else if (mce.Method.Name == "NotLike")
return string.Format("({0} Not like {1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
else if (mce.Method.Name == "In")
return string.Format("{0} In ({1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
else if (mce.Method.Name == "NotIn")
return string.Format("{0} Not In ({1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
}
else if (exp is ConstantExpression)
{
ConstantExpression ce = ((ConstantExpression)exp);
if (ce.Value == null)
return "null";
else if (ce.Value is ValueType)
return ce.Value.ToString();
else if (ce.Value is string || ce.Value is DateTime || ce.Value is char)
return string.Format("'{0}'", (ce.Value as string).Replace("'", "''"));
}
else if (exp is UnaryExpression)
{
UnaryExpression ue = ((UnaryExpression)exp);
return ExpressionRouter(ue.Operand);
}
return null;
}
// 表达式类型转换。
static string ExpressionTypeCast(ExpressionType type)
{
switch (type)
{
case ExpressionType.And:
case ExpressionType.AndAlso:
return " AND ";
case ExpressionType.Equal:
return " =";
case ExpressionType.GreaterThan:
return " >";
case ExpressionType.GreaterThanOrEqual:
return ">=";
case ExpressionType.LessThan:
return "<";
case ExpressionType.LessThanOrEqual:
return "<=";
case ExpressionType.NotEqual:
return "<>";
case ExpressionType.Or:
case ExpressionType.OrElse:
return " Or ";
case ExpressionType.Add:
case ExpressionType.AddChecked:
return "+";
case ExpressionType.Subtract:
case ExpressionType.SubtractChecked:
return "-";
case ExpressionType.Divide:
return "/";
case ExpressionType.Multiply:
case ExpressionType.MultiplyChecked:
return "*";
default:
return null;
}

}

基本改动不大,即使你用的lambda条件里是变量,也用 var result = Expression.Lambda(exp).Compile().DynamicInvoke();动态计算出他的值,暂时就先这么用着。

这么做为了查询之前条件拼进sql,而不是查完全集再用lambda表达式二次筛选。

增删改的方法基本就是拼sql没什么技术含量就不介绍了,亲们看代码吧。

Logic.Emit.cs说起来也不知道怎么用好,因为这部分就是查表名反射属性构造类型,对于没有类型就没办法谈增删改,所以准备以后写成类库的生成器,查库所有表,反射,保存成Dll。

我在做这个的时候,那个给字段加属性标签的代码查了很久,最后在老外的文章里找到了,就是这一段:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 ConstructorInfo classCtorInfo = typeof(DescriptionAttribute).GetConstructor(ctorParams);
CustomAttributeBuilder myCABuilder = new CustomAttributeBuilder(
classCtorInfo,
new object[] { "IsPrimaryKey" });
propertyBuilder.SetCustomAttribute(myCABuilder);

基本上就介绍完了。

这些东西目前只是个雏形,因为还有很多值得去做的东西,比如说缓存,分页,前台交互方式等等,希望能和大家多交流,去借鉴一些优秀框架的亮点,来不断的完善。尤其是期望能用linq to Json去和前台交互,找一套和json结合完美的js控件,界面用工具拖拽方式生成,再搭配dev,telerik等优秀的服务端控件。目标就是用最少的代码,完成最烦的事。

希望大家看完多提提意见,帮助帮助我,也可以加这个群91132696交流,目前只有我:)。源代码Corehttp://files.cnblogs.com/zakkia/Core.rar

转载于:https://www.cnblogs.com/zakkia/archive/2011/10/27/2226654.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值