自定义ORM系列(一)利用attribute实现简单的reader=>entity和reader=>List<entity>映射

简介:

我不知道NH的ORM具体如何实现的,我的想法就是通过字段名称和属性名称的对应关系来实现赋值。

  简单的类型比较好做,直接赋值就可以了。简单类型是说int,string之类的。

  有几个需要注意的地方:

  1 属性的类型是另外一个类

  2 属性是一个集合

  3 类有两个属性的类型是同一个类,例如:种子有用量及其单位,和产量及其单位,用量的单位和产量的单位是一个类型

  4 属性嵌套,就是属性的这个类型里面的属性还可能是另外一个类

  

  解决办法:

  1 用不同的attribute,普通的类型直接赋值,另外一个类的话就交给另外一个类去负责具体的映射

  分两次映射,然后集合赋值给商品的属性,觉得不是很好,有没有更好的办法呢?

  3 添加前缀来区分两个相同类型的不同属性

  4 嵌套,一层一层解决

  还有就是关于集合,例如:商品的包装规格集合。如何映射呢?是不是需要集合的时候,再次根据商品的ID查询包装规格集合,然后赋值给商品的包装规格属性呢?

  那就是两次访问数据库了,我想要一次访问,可以实现吗?

  结果集就是下面的格式,第一个table是商品,第二个table是包装规格,循环第一个table映射出来一个商品,但是在映射的时候如果发现属性是List类型,实际上是需要第二个结果集来配合了。如何传第二个的结果集呢?我想不出来。我的解决办法就是一个一个的映射,先映射商品,赋值给一个商品的实例。然后映射包装规格,赋值给一个List,然后把这个List赋值给商品的包装规格属性。

  不知道能否在映射商品的同时就映射包装规格集合吗?

  

  数据库的查询结果

  

 

  先定义两个attribute,一个用在属性上面,用来映射列

代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;

namespace  BeautyCode.SQLite.ConApp.Common
{
    [AttributeUsage(AttributeTargets.Property)]
    
public   class  ColumnAttribute : Attribute
    {
        
private   string  _columnType;
        
///   <summary>
        
///  数据库字段类型
        
///   </summary>
         public   string  ColumnType
        {
            
get  {  return  _columnType; }
            
set  { _columnType  =  value; }
        }
        
private   string  _columnName;
        
///   <summary>
        
///  数据库字段名称
        
///   </summary>
         public   string  ColumnName
        {
            
get  {  return  _columnName; }
            
set  { _columnName  =  value; }
        }
        
private   int  _length;
        
///   <summary>
        
///  数据库字段长度
        
///   </summary>
         public   int  Length
        {
            
get  {  return  _length; }
            
set  { _length  =  value; }
        }
        
private   bool  _isIdentity;
        
///   <summary>
        
///  是否标识列
        
///   </summary>
         public   bool  IsIdentity
        {
            
get  {  return  _isIdentity; }
            
set  { _isIdentity  =  value; }
        }

        
public  ColumnAttribute( string  columnName,  string  columnType,  int  len,  bool  isIdentity)
        {
            
this ._columnType  =  columnType;
            
this ._columnName  =  columnName;
            
this ._length  =  len;
            
this ._isIdentity  =  isIdentity;
        }
        
public  ColumnAttribute( string  columnName)
            : 
this (columnName,  string .Empty,  0 false )
        {

        }
    }
}

  一个用在属性是复杂类型,也就是说属性的类型是另外一个类

  

代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;

namespace  BeautyCode.SQLite.ConApp.Common
{
    [AttributeUsage(AttributeTargets.Property)]
    
public   class  ReferenceAttribute : Attribute
    {
        
private  Type _referenceClassType;

        
public  Type ReferenceClassType
        {
            
get  {  return  _referenceClassType; }
            
set  { _referenceClassType  =  value; }
        }
        
private   string  _preFix;

        
public   string  PreFix
        {
            
get  {  return  _preFix; }
            
set  { _preFix  =  value; }
        }

        
private  ReferenceType _referenceType;

        
public  ReferenceType ReferenceType
        {
            
get  {  return  _referenceType; }
            
set  { _referenceType  =  value; }
        }
        
public  ReferenceAttribute(Type type,  string  preFix,ReferenceType referenceType)
        {
            
this ._referenceClassType  =  type;
            
this ._preFix  =  preFix;
            
this ._referenceType  =  referenceType;
        }

    }
    
public   enum  ReferenceType
    {
        Ojbect,
        Collection
    }
}

 

  给这两种attribute类型定义两个映射方法

  

代码
public    class  ColumnMapper
    {
       
public   static   void  ColToProperty( ref  PropertyInfo p, object  entity, IDataReader reader, string  preFix)
       {
           
string  columnName  =   string .IsNullOrWhiteSpace(preFix)  ?  p.Name : preFix  +  p.Name;
          
               
if  (p.PropertyType.IsEnum)
               {
                   p.SetValue(entity, Enum.Parse(p.PropertyType, reader[columnName].ToString()), 
null );
               }
               
else
               {
                   p.SetValue(entity, reader[columnName], 
null );
               }
          
       }
    }

 
public   class  ReferenceMapper
    {
        
public   static   object    ReferenceToEntity( Type type,  string  preFix, IDataReader  reader, Common.ReferenceType referenceType)
        {
            
string  columnName  =   string .Empty;
           
object  obj  =  Activator.CreateInstance(type);

            PropertyInfo[] ps 
=  obj.GetType ().GetProperties();

            
for  ( int  i  =   0 ; i  <  ps.Length; i ++ )
            {
                columnName 
=   string .IsNullOrWhiteSpace(preFix)  ?  ps[i].Name : preFix  +  ps[i].Name;
                
object [] attributes  =  ps[i].GetCustomAttributes( false );
                
if  (attributes.Length  >   0 )
                {
                    
if  (referenceType  ==  Common.ReferenceType.Ojbect)
                    {
                        
if  (attributes[ 0 is  Common.ColumnAttribute)
                        {
                            
if  ( string .IsNullOrWhiteSpace(reader[columnName].ToString()))
                                
continue ;
                            ColumnMapper.ColToProperty(
ref  ps[i], obj, reader, preFix);
                        }
                        
if  (attributes[ 0 is  Common.ReferenceAttribute)
                        {
                            ps[i].SetValue(obj, ReferenceMapper.ReferenceToEntity((attributes[
0 as  Common.ReferenceAttribute).ReferenceClassType,
                               (attributes[
0 as  Common.ReferenceAttribute).PreFix, reader, (attributes[ 0 as  Common.ReferenceAttribute).ReferenceType),  null );
                        }
                    }
                }
            }
            
return  obj;
        }
    }

 

  实例实体类

  

 

代码
 [Flags]
    
public   enum  ProductType
    {
        Seed 
=   1 ,
        Fertilizer 
=   2 ,
        Pesticide 
=   4
    }
    
public   class  Seed : Common.BaseEntity
    {
        [Column(
" SeedID " )]
        
public  Guid SeedID
        { 
get set ; }
        [Column(
" SeedName " )]
        
public   string  SeedName
        { 
get set ; }
        [Column (
" ProductType " )]
        
public  ProductType ProductType
        {
            
get ;
            
set ;
        }
        [Column(
" PlantAmount " )]
        
public   decimal  PlantAmount
        { 
get set ; }
        [Reference(
typeof (Unit),  " PlantAmount " , Common.ReferenceType.Ojbect )]
        
public  Unit PlantAmountUnit
        { 
get set ; }
        [Column(
" OutputAmount " )]
        
public   decimal  OutputAmount
        { 
get set ; }
        [Reference(
typeof (Unit),  " OutputAmount " , Common.ReferenceType.Ojbect )]
        
public  Unit OutputAmountUnit
        { 
get set ; }
        
// [Reference (typeof(SeedPkgSpec),"", Common.ReferenceType.Collection )]
         public  List < SeedPkgSpec >  PkgSpecs
        {
            
get ;
            
set ;
        }
    }

 

SeedPkgSpec
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  BeautyCode.SQLite.ConApp.Common;

namespace  BeautyCode.SQLite.ConApp.Entity
{
    
public   class  SeedPkgSpec : Common.BaseEntity 
   {
       [Column(
" PkgSpecID " )]
       
public  Guid PkgSpecID
       { 
get set ; }
       [Column(
" SeedID " )]
       
public  Guid SeedID 
       { 
get set ; }
       [Column(
" PkgAmount " )]
       
public   decimal  PkgAmount
       { 
get set ; }
       [Reference(
typeof (Unit ), " PkgAmount " , Common.ReferenceType.Ojbect ) ]
       
public  Unit PkgUnit
       { 
get set ; }
       [Reference(
typeof (PkgSpec),  "" ,  Common.ReferenceType.Ojbect )]
       
public  PkgSpec PkgSpec
       {
           
get ;
           
set ;
       }
    }
}

 

 

代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  BeautyCode.SQLite.ConApp.Common;

namespace  BeautyCode.SQLite.ConApp.Entity
{
   
public    class  PkgSpec:Common.BaseEntity 
    {
       [Column(
" PkgSpecCode " )]
       
public   string  PkgSpecCode
       { 
get set ; }
       [Column(
" PkgSpecName " )]
       
public   string  PkgSpecName
       { 
get set ; }
    }
}

 

 

代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  BeautyCode.SQLite.ConApp.Common;

namespace  BeautyCode.SQLite.ConApp.Entity
{
    
public   class  Unit : Common.BaseEntity 
    {
        [Column(
" UnitCode " )]
        
public   string  UnitCode 
        { 
get set ; }
        [Column(
" UnitCnName " )]
        
public   string  UnitCnName
        { 
get set ; }
        [Column( 
" UnitEnName " )]
        
public   string  UnitEnName
        { 
get set ; }
    }
}

  映射接口,每个实体实现下面的接口

 

代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Data;


namespace  BeautyCode.SQLite.ConApp.EntityMapper
{
    
public   interface   IEntityMapper < T >   where  T:Common.BaseEntity 
    {
        T RowToEntity(IDataReader  reader);

        DataRow EntityToRow(T entity);
    }
}

 

 

代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Reflection;
using  System.Data;

namespace  BeautyCode.SQLite.ConApp.EntityMapper
{
    
public   class  SeedMapper : IEntityMapper < Entity.Seed >
    {
        
#region  IEntityMapper<Seed> Members

        
public  Entity.Seed RowToEntity(IDataReader reader)
        {
            Entity.Seed entity 
=   new  Entity.Seed();

            PropertyInfo[] ps 
=   typeof (Entity.Seed).GetProperties();

            
for  ( int  i  =   0 ; i  <  ps.Length; i ++ )
            {
                
object [] attributes  =  ps[i].GetCustomAttributes( false );
                
if  (attributes.Length  >   0 )
                {
                    
if  (attributes[ 0 is  Common.ColumnAttribute)
                    {
                        ColumnMapper.ColToProperty(
ref  ps[i], entity, reader,  null );
                    }
                    
if  (attributes[ 0 is  Common.ReferenceAttribute)
                    {
                        ps[i].SetValue(entity, ReferenceMapper.ReferenceToEntity((attributes[
0 as  Common.ReferenceAttribute).ReferenceClassType,
                             (attributes[
0 as  Common.ReferenceAttribute).PreFix, reader, (attributes[ 0 as  Common.ReferenceAttribute).ReferenceType),  null );

                    }
                }

            }
            
return  entity;
        }



        
public  System.Data.DataRow EntityToRow(Entity.Seed entity)
        {
            
throw   new  NotImplementedException();
        }

        
#endregion
    }
}

 

 

代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Reflection;
using  System.Data;

namespace  BeautyCode.SQLite.ConApp.EntityMapper
{
    
public   class  SeedPkgSpecMapper:IEntityMapper < Entity.SeedPkgSpec  >
    {
        
#region  IEntityMapper<SeedPkgSpec> Members

        
public  Entity.SeedPkgSpec RowToEntity(IDataReader  reader)
        {
            Entity.SeedPkgSpec entity 
=   new  Entity.SeedPkgSpec();

            PropertyInfo[] ps 
=   typeof (Entity.SeedPkgSpec).GetProperties();

            
for  ( int  i  =   0 ; i  <  ps.Length; i ++ )
            {
                
object [] attributes  =  ps[i].GetCustomAttributes( false );
                
if  (attributes.Length  >   0 )
                {
                    
if  (attributes[ 0 is  Common.ColumnAttribute)
                    {
                        
if  ( string .IsNullOrWhiteSpace(reader[ps[i].Name].ToString()))
                            
continue ;
                        ColumnMapper.ColToProperty(
ref  ps[i], entity, reader,  null );
                    }
                    
if  (attributes[ 0 is  Common.ReferenceAttribute)
                    {
                        ps[i].SetValue(entity, ReferenceMapper.ReferenceToEntity((attributes[
0 as  Common.ReferenceAttribute).ReferenceClassType,
                             (attributes[
0 as  Common.ReferenceAttribute).PreFix, reader, (attributes[ 0 as  Common.ReferenceAttribute).ReferenceType),  null );

                    }
                }

            }
            
return  entity;
        }

        
public  System.Data.DataRow EntityToRow(Entity.SeedPkgSpec entity)
        {
            
throw   new  NotImplementedException();
        }

        
#endregion
    }
}

 

 

代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Reflection;

namespace  BeautyCode.SQLite.ConApp.EntityMapper
{
    
public   class  UnitMapper:IEntityMapper < Entity.Unit >
    {
        
#region  IEntityMapper<Unit> Members

        
public  Entity.Unit RowToEntity(System.Data.IDataReader reader)
        {
            Entity.Unit entity 
=   new  Entity.Unit();

            PropertyInfo[] ps 
=   typeof (Entity.Unit).GetProperties();

            
for  ( int  i  =   0 ; i  <  ps.Length; i ++ )
            {
                
object [] attributes  =  ps[i].GetCustomAttributes( false );
                
if  (attributes.Length  >   0 )
                {
                    
if  (attributes[ 0 is  Common.ColumnAttribute)
                    {
                        
if  ( string .IsNullOrWhiteSpace(reader[ps[i].Name].ToString()))
                            
continue ;
                        ColumnMapper.ColToProperty(
ref  ps[i], entity, reader,  null );
                    }
                    
if  (attributes[ 0 is  Common.ReferenceAttribute)
                    {
                        ps[i].SetValue(entity, ReferenceMapper.ReferenceToEntity((attributes[
0 as  Common.ReferenceAttribute).ReferenceClassType,
                             (attributes[
0 as  Common.ReferenceAttribute).PreFix, reader, (attributes[ 0 as  Common.ReferenceAttribute).ReferenceType),  null );

                    }
                }

            }
            
return  entity;
        }

        
public  System.Data.DataRow EntityToRow(Entity.Unit entity)
        {
            
throw   new  NotImplementedException();
        }

        
#endregion
    }
}

 

  上面的代码结构其实还是可以优化的,因为每个实体类的映射方法,里面的代码大量的重复,只是初始化的类型不一样,还有重构的余地。

  目前还差的就是映射集合,在映射商品的时候一起映射集合。

  项目可以从http://beautycode.codeplex.com/下载,或者是/Files/virusswb/BeautyCode.SQLite.ConApp.rar,希望大家踊跃参与讨论。

 

  刚才稍微重构了一下,就是实体类对应的每个映射类,其实可以抽象一个抽象类,然后实体类的映射类继承抽象类,抽象类实现接口,包含具体的实现,如果实体类的映射类需要重写的话,就override,不需要的话,默认也可以使用。

  

BaseEntityMapper
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Reflection;
using  System.Data;

namespace  BeautyCode.SQLite.ConApp.EntityMapper
{
    
public   abstract   class  BaseEntityMapper < T >  : IEntityMapper < T >   where  T : Common.BaseEntity
    {

        
#region  IEntityMapper<T> Members

        
public   virtual  T RowToEntity(IDataReader reader)
        {
            T entity 
=  Activator.CreateInstance < T > ();

            PropertyInfo[] ps 
=   typeof (T).GetProperties();

            
for  ( int  i  =   0 ; i  <  ps.Length; i ++ )
            {
                
object [] attributes  =  ps[i].GetCustomAttributes( false );
                
if  (attributes.Length  >   0 )
                {
                    
if  (attributes[ 0 is  Common.ColumnAttribute)
                    {
                        ColumnMapper.ColToProperty(
ref  ps[i], entity, reader,  null );
                    }
                    
if  (attributes[ 0 is  Common.ReferenceAttribute)
                    {
                        ps[i].SetValue(entity, ReferenceMapper.ReferenceToEntity((attributes[
0 as  Common.ReferenceAttribute).ReferenceClassType,
                             (attributes[
0 as  Common.ReferenceAttribute).PreFix, reader, (attributes[ 0 as  Common.ReferenceAttribute).ReferenceType),  null );

                    }
                }

            }
            
return  entity;
        }

        
public   virtual  DataRow EntityToRow(T entity)
        {
            
throw   new  NotImplementedException();
        }

        
#endregion
    }
}

 

 

  具体实体类的映射类就可以得到简化

 

代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Reflection;
using  System.Data;

namespace  BeautyCode.SQLite.ConApp.EntityMapper
{
    
public   class  SeedMapper : BaseEntityMapper < Entity.Seed  >
    {
        
    }
}

 




本文转自 virusswb 51CTO博客,原文链接:http://blog.51cto.com/virusswb/461370,如需转载请自行联系原作者

目录
相关文章
|
JavaScript
Vue Antdv 列表(table、list)自定义空数据状态UI
Vue Antdv 列表(table、list)自定义空数据状态UI
628 0
|
6月前
|
Python
【已解决】AttributeError: ‘Index‘ object has no attribute ‘to_list‘
【已解决】AttributeError: ‘Index‘ object has no attribute ‘to_list‘
|
Java
自定义list To HashMap工具类
自定义list To HashMap工具类
45 0
|
算法 C++ 容器
<C++> list容器本质|常用接口|自定义排序规则(下)
<C++> list容器本质|常用接口|自定义排序规则
113 0
|
PHP
PHP - Laravel 查看自定义路由列表 (php artisan route:list)
PHP - Laravel 查看自定义路由列表 (php artisan route:list)
250 0
|
存储 C++ 容器
<C++> list容器本质|常用接口|自定义排序规则(上)
<C++> list容器本质|常用接口|自定义排序规则
114 0
pageable 使用自定义list实现分页
pageable 使用自定义list实现分页
135 0
AttributeError: ‘list‘ object has no attribute ‘ndim‘
AttributeError: ‘list‘ object has no attribute ‘ndim‘
193 0
|
Python
AttributeError: 'list' object has no attribute 'ndim'
AttributeError: 'list' object has no attribute 'ndim'
540 0
|
云计算
PIE-engine 教程 ——云计算当中的map()映射函数list列表映射案例分析
PIE-engine 教程 ——云计算当中的map()映射函数list列表映射案例分析
125 0
PIE-engine 教程 ——云计算当中的map()映射函数list列表映射案例分析