吵吵   2014-09-13  阅读:2,658

对象关系映射,靠纯手打,是个超级繁琐又类的苦力活,即便它能给你再高的运行效率,但是也会损失开发效率。

c#在netframework中其实已经提供了ORM框架了,叫做entity framework,这个框架其实已经做的蛮好的了,但是框架实在是太重,重到写出来的代码在配置不那么好的电脑上跑起来都卡顿。

因此我们决定自己写这么一个框架,一来重在轻量;二来,就是想探探路,看看ORM框架到底是怎么做出来的。

当然,让我自己凭空造楼是做不到的,但是我们可以借鉴,尤其是在互联网这么发达的时代,去github看看别的的开源代码就OK了。


一、反射。

首先我们要解决的就是当从数据库中取出值来了之后,怎么直接赋值给相应的对象的属性的问题,我们记得,传统的做法就是

dt.Rows[i][“ID”]

这么一个一个字段去写,碰到字段比较多的表,那就会打半天了。

反射,就是要获得该类的变量的名称,然后赋值给该变量:

public List<T> ExecSelect<T>(string sqlCmd) where T : new()
        {
            List<T> list = new List<T>();
            DataTable dt = Select(sqlCmd);

            if (dt.Rows.Count == 0)
            {
                return list;
            }

            PropertyInfo[] properties = ReflectionHelper.GetProperties(new T().GetType());

            for (int i=0;i<dt.Rows.Count;i++)
            {
                T entity = new T();
                foreach (PropertyInfo property in properties)
                {
                    String name = property.Name;
                    ReflectionHelper.SetPropertyValue(entity, property, dt.Rows[i][name]);
                }
                list.Add(entity);
            }

            return list;

        }

以上的T就是一种泛型,至于泛型是什么,自行百度。

GetProperties函数即是泛型用于获取类的变量的方法,它有一些参数,包括获取变量为public修饰等等参数:

 public static PropertyInfo[] GetProperties(Type type)
        {
            return type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
        }

二、Value.

既然我们已经通过GetProperties获取了该类的属性,那么通过SetValue直接给其赋值就好了,问题是,如果我们从数据库中取出来的值和它不匹配呢,因此我们需要转化Value类型。

if (Convert.IsDBNull(value) || (value == null))
            {
                return null;
            }

            string typeName = type.FullName.ToString();
            System.Console.WriteLine(typeName);

            if (type == typeof(System.Nullable<UInt16>))
            {
                value = Convert.ToUInt16(value);
            }
            else if (type == typeof(System.Nullable<UInt32>))
            {
                value = Convert.ToUInt32(value);
            }
            else if (type == typeof(System.Nullable<UInt64>))
            {
                value = Convert.ToUInt64(value);
            }
            else if (type == typeof(System.Nullable<Int32>))
            {
                value = Convert.ToInt32(value);
            }
            else if (type == typeof(System.Nullable<Int64>))
            {
                value = Convert.ToInt64(value);
            }

            switch (typeName)
            {
                case "System.String":
                    if (!isNullOrEmpty(value))
                        value = value.ToString();
                    break;
                case "System.Boolean":
                    if (!isNullOrEmpty(value))
                        value = Convert.ToBoolean(value);
                    break;
                case "System.Int16":
                    if (!isNullOrEmpty(value))
                        value = Convert.ToInt16(value);
                    break;
                case "System.Int32":
                    if (!isNullOrEmpty(value))
                        value = Convert.ToInt32(value);
                    break;
                case "System.Int64":
                    if (!isNullOrEmpty(value))
                        value = Convert.ToInt64(value);
                    break;
                case "System.Double":
                    if (!isNullOrEmpty(value))
                        value = Convert.ToDouble(value);
                    break;
                case "System.Float":
                    if (!isNullOrEmpty(value))
                        value = Convert.ToDouble(value);
                    break;
                case "System.Single":
                    if (!isNullOrEmpty(value))
                        value = Convert.ToDouble(value);
                    break;
                case "System.Decimal":
                    if (!isNullOrEmpty(value))
                        value = Convert.ToDecimal(value);
                    break;
                case "System.DateTime":
                    if (!isNullOrEmpty(value))
                        value = Convert.ToDateTime(value);
                    break;
            }

            return value;
        }

三、反射与动态编译。

Reflection真的是个好东西,但是net4.0后会有一个更好的东西:dynamic,要知道反射其实是很费效率的,但是动态编译就会快的多,如果你不理解dynamic,那么以下的例子就会告诉你这两者的区别:

public void test()
        {
            SomeClass c = new SomeClass();

            PropertyInfo property = c.GetType().GetProperties()[0];

            StartTest("begin reflection.");

            for (int i = 0; i < 1000000; i++)
            {
                property.SetValue(c, i, null);
            }

            EndTest("end reflection");

            IDynamicPropertyInfo dproperty = new DynamicType(c.GetType()).GetProperties()[0];

            StartTest("begin dynamic.");

            for (int i = 0; i < 1000000; i++)
            {
                dproperty.SetValue(c, i, null);
            }

            EndTest("end dynamic");
        }

那么这两者的时间差呢:

—— Test started: Assembly: Pixysoft.Framework.Reflection.dll ——

begin reflection.
end reflection
00:00:09.0625000

begin dynamic.
end dynamic
00:00:00.0468750

差别就太远了,所以如果你觉得因为反射你的程序变慢了,不如试试动态编译。

吵吵微信朋友圈,请付款实名加入:

吵吵 吵吵

2条回应:“c# 轻量ORM框架开发之反射与动态编译”

  1. 冯禹赫说道:

    受教[鼓掌]

  2. 小菜说道:

    SetPropertyValue 这个方法在哪

发表评论

电子邮件地址不会被公开。 必填项已用*标注