• DataTable转换为Model


    在MVC或者EF等框架下,SQL查询的数据会直接转换成相应的Model(模型),有时我们通过其他方式得到一个DataTable,比如直接执行SQL或者代码内部产生,这时为了能更好的与其他代码结合,可能会需要转换成相应的Model,那我们要怎么处理呢?

    只有一个DataTable,要转换成模型,很自然的想到,利用反射。因为只有反射才能得到相应的类型,得到相应的属性。那要反射,我们首先要得到的就是程序集。一般的我们的模型会做成一个单独的类库,比如DemoModel,里面含有很多具体的模型类,比如Student,Company等。所以我们可以直接以程序集名称的方式来载入程序集,代码如下

    string assemblyName = nameof(KingModel);
    Assembly assembly = Assembly.Load(assemblyName);

    得到了程序集assemble之后,我们要知道DataTable对应的数据类型,这时我们可以根据DataTable的TableName来。有人说,从数据库查到的是一个数据集DataSet,里面的DataTable是dt1、dt2这些无法对应数据类型的名称,那要怎么办?

    这个问题,其实也不难处理。一种比较直接的方案,就是从数据库中查到这个表的表名,然后放到查询的DataSet中一起返回,之后按顺序将TableName赋值。也可以在客户端写好生成的SQL,然后与要查询的SQL一起执行,然后得到的第一个DataTable就是表名列表。

    在TableName对应上了之后,我们就以这个TableName来获取数据类型。这里需要特别注意,在利用程序集来获取类型时,类型的字符串必须是包含命名空间的完全限定名,否则会获取类型失败或者为null值,代码如下

    string modelClassName = "";
    modelClassName = $"{assemblyName}." + table.TableName;
    if (_typeDict.ContainsKey(modelClassName))
    {
         type = _typeDict[modelClassName];
    }
    else
    {
         type = assembly.GetType(modelClassName);
        _typeDict.Add(modelClassName, type);
    }
    注意,为了减小类型获取而消耗的时候,我们作了一个内部缓存,即建立一个静态的类型字典_typeDict。

            /// <summary>
            /// 类型字典.
            /// Key:类型名称.
            /// Value:类型.
            /// </summary>
            private static Dictionary<string, Type> _typeDict = new Dictionary<string, Type>();

    得到了类型Type之后,我们就可以通过程序集来创建实例,然后通过反射获取属性来给对象赋值了,代码如下

    List<object>  modelList=new List<object>;
    foreach (DataTable table in ds.Tables)
                {
                    modelClassName = $"{assemblyName}." + table.TableName;
                    if (_typeDict.ContainsKey(modelClassName))
                    {
                        type = _typeDict[modelClassName];
                    }
                    else
                    {
                        type = assembly.GetType(modelClassName);
                        _typeDict.Add(modelClassName, type);
                    }
    
                    if (type == null)
                    {
                        throw new Exception($"{modelClassName} not exist.");
                    }
    
                    if (_propertyInfoDict.ContainsKey(modelClassName))
                    {
                        propertyInfos = _propertyInfoDict[modelClassName];
                    }
                    else
                    {
                        propertyInfos = type.GetProperties();
                        _propertyInfoDict.Add(modelClassName, propertyInfos);
                    }
    
                    foreach (DataRow row in table.Rows)
                    {
                        instance = assembly.CreateInstance(modelClassName);
                        modelList.Add(instance);
                        foreach (var propertyInfo in propertyInfos)
                        {
                            if (DBNull.Value == row[propertyInfo.Name])
                            {
                                continue;
                            }
                            propertyInfo.SetValue(instance, row[propertyInfo.Name], null);
                        }
                    }
                }
    其中_propertyInfoDict也是用静态变量作了缓存处理,主要是因为反射耗时。

    当然,如果只有一个DataTable,而我们很明确的知道要转换成什么样的Model,那么就可以不用反射来查找类型,直接new 相应的model,然后用反射来赋值就可以了。

    List<TModel>  modelList=new List<TModel>;
    
                    modelClassName = $"{assemblyName}." + table.TableName;
    		type=typeof(TModel);
    
                    if (type == null)
                    {
                        throw new Exception($"{modelClassName} not exist.");
                    }
    
                    if (_propertyInfoDict.ContainsKey(modelClassName))
                    {
                        propertyInfos = _propertyInfoDict[modelClassName];
                    }
                    else
                    {
                        propertyInfos = type.GetProperties();
                        _propertyInfoDict.Add(modelClassName, propertyInfos);
                    }
    
                    foreach (DataRow row in table.Rows)
                    {
                        instance = assembly.CreateInstance(modelClassName);
                        modelList.Add(instance);
                        foreach (var propertyInfo in propertyInfos)
                        {
                            if (DBNull.Value == row[propertyInfo.Name])
                            {
                                continue;
                            }
                            propertyInfo.SetValue(instance, row[propertyInfo.Name], null);
                        }
                    }
    或许有人会说,赋值的时候为什么要用反射?直接赋值不行吗?如果知道具体的类型是可以的,但我们并不清楚,只是以类型TModel的形式来赋值的,所以需要反射。而且即便是直接赋值,后续只要有增减字段就需要维护,这会是个麻烦的问题。

    这里需要注意,DataTable中不能有复杂的数据类型,比如List。原则上这种情况不应该出现的,因为模型源于数据库,就应该是int、float、DateTime、string等一般的类型。

    转载请注明出处。



  • 相关阅读:
    TCP粘包的拆包处理
    字节序列化
    同步,异步,阻塞和非阻塞
    用Doxygen生成文档
    Visual Studio新建的源文件的默认编码
    Boost编程之获取可执行文件的当前路径
    特征点寻找的基础数据结构和函数
    寻找Harris、Shi-Tomasi和亚像素角点
    特征点的基本概念和如何找到它们
    工业相机与普通相机的差别
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7604917.html
Copyright © 2020-2023  润新知