打造轻量级的实体类数据容器

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介:

这里有三个关键词:轻量级实体类数据容器,还有一个潜在的关键词:通用。这几个名词之间有什么联系呢?

    一般来说,操作实体类往往伴随着一个实体类集合,而这些集合就是实体类的容器,在这里我将“容器”视作一个比集合更广泛的概念,例如Entity Framework做了一个重量级的容器ObjectContext,用于与作为对象(这些对象为 EDM 中定义的实体类型的实例)的数据进行交互。

    实体类与容器没有必然关系,例如DataSet也是一个容器,它存储并操作DataTable,而DataTable也可以看做是各个单元格数据的容器...

    但是,这些“数据容器”还是显得比较重量级,里面有太多要交互的子对象,为此我在PDF.NET(PWMIS数据开发框架)中定义了一个非常轻量级的实体数据容器,它存储数据的原则很简单,就是一个object[][],外加一个对应的字段名称数组,其它诸如表的元素据等信息都没有存储,也就是下面程序中的3个私有对象:

 

复制代码
     ///   <summary>
    
///  实体数据容器
    
///   </summary>
     public   class  EntityContainer
    {
        
private   string [] fieldNames;
        
private  List < object [] >  Values;
        
private   object [] currValue;

    }
复制代码

 

实体容器接收一个DataReader对象,将其中的数据读入Values 数组,下面是相应的方法代码:

 

复制代码
         ///   <summary>
        
///  执行DataReader查询,并将查询结果缓存
        
///   </summary>
        
///   <param name="reader"> 数据阅读器 </param>
        
///   <returns> 结果行数 </returns>
         public   int  Execute(IDataReader reader)
        {
            List
< object [] >  list  =   new  List < object [] > ();
            
using  (reader)
            {
                
if  (reader.Read())
                {
                    
int  fcount  =  reader.FieldCount;
                    fieldNames 
=   new   string [fcount];
                    
object [] values  =   null ;

                    
for  ( int  i  =   0 ; i  <  fcount; i ++ )
                        fieldNames[i] 
=  reader.GetName(i);

                    
do
                    {
                        values 
=   new   object [fcount];
                        reader.GetValues(values);
                        list.Add(values);
                    } 
while  (reader.Read());

                }
            }
            
this .Values  =  list;
            
return  list.Count;
        }
复制代码

程序中使用 reader.GetValues(values) 方法,它不必对每列进行数据读取,所以数据读取的效率较高。

现在数据存放进去了,如何使用呢?为了做到通用,具体每个数据的使用还是交给使用者自己去处理吧,所以采用一个委托方法来处理:

 

复制代码
        ///   <summary>
        
///  采用自定义的映射方式,将数据容器中的数据映射到指定的类中 
        
///   </summary>
        
///   <typeparam name="TResult"> 结果类型 </typeparam>
        
///   <param name="fun"> 处理数据的方法 </param>
        
///   <returns></returns>
         public  IEnumerable < TResult >  Map < TResult > (Func < TResult >  fun)  where  TResult :  class new ()
        {
            
if  ( this .Values  !=   null   &&   this .fieldNames  !=   null )
            {
                
foreach  ( object [] itemValues  in   this .Values)
                {
                    TResult t 
=   new  TResult();
                    
this .currValue  =  itemValues;
                    fun(t);
                    
yield   return  t;
                }
            }
            
else
            {
                
throw   new  Exception( " EntityContainer 错误,调用该方法前请先调用Execute 方法。 " );
            }
        }
复制代码

下面是该方法的使用示例:

 

复制代码
            EntityContainer ec  =   new  EntityContainer(q, db);
            ec.Execute();
           
 var mapUser2 =  ec.Map < User > ((e)  =>  
            {
                e.Age 
=  ec.GetItemValue < int > ( " Age " );
                e.ID 
=  ec.GetItemValue < int > ( " ID " );
                e.Name 
=  ec.GetItemValue < string > ( " name " ); // 不区分大小写
                 return  e; 
            }
            ).ToList ();
复制代码

 除了可以使用 GetItemValue<T>(string fieldName) 方法来获取迭代的当前行的某列数据外,也可以使用 GetItemValue<T>(int fieldIndex) 方法。

另外,还提供了一个将数据映射到PDF.NET实体类的方法,下面是方法的定义:

 

复制代码
         ///   <summary>
        
///  将数据从容器中映射到实体中
        
///   </summary>
        
///   <typeparam name="T"></typeparam>
        
///   <returns></returns>
         public  IEnumerable < T >  Map < T > ()  where  T : EntityBase{
             //具体代码略
        }
复制代码

上面的测试例子中,User类是一个实体类,所以可以用下面的方式直接获取该类的实例对象集合:

 

            EntityContainer ec  =   new  EntityContainer(q, db);
            ec.Execute();
            var mapUser1 
=  ec.Map < User > ().ToList ();

在Map方法中,可以映射出任意PDF.NET实体类,或者其它自定义的POCO实体类,而且没有映射次数限制。看到这里聪明的你也许要问了,上面的例子可以映射User之外的实体吗?答案是完全可以!

先看一个例子,我们假设系统中还存在一个实体类 Group,我们使用PDF.NET的OQL表达式写一个支持两个实体连接查询的语句:

 

OQL q = OQL.From(user)
         .
InnerJoin (group)  //连接Group实体
         .On(user.GroupID,
group.ID)
         .Select(user.ID,user.Name,group.GroupName) 
//选 取指 定的字段

下面就可以映射出两个实体集合了:

 

            EntityContainer ec  =   new  EntityContainer(q, db);
            ec.Execute(); 
//可以省略此行调用
            var mapUser1 
=  ec.Map < User > ().ToList ();
            var mapGroup1
ec.Map < Group > ().ToList();

如果觉得这样分别使用两个实体对象集合( user和group)比较麻烦,那么再自定义一个“用户机构”类即可:

 

复制代码
  class  UserGroup 
{
    
int  ID{ get ; set ;}
    
string  Name{ get ; set ;}
    
string  GroupName{ get ; set ;}
}
复制代码

之后,可以像下面这样来使用数据:

 

复制代码
            EntityContainer ec  =   new  EntityContainer(q, db);
            //ec.Execute();//可以省略此行调用

            var mapEntity
=  ec.Map < UserGroup > ((e)  =>  
            {
                e.GroupName 
=  ec.GetItemValue < int > ( " GroupName " );
                e.ID 
=  ec.GetItemValue < int > ( " ID " );
                e.Name 
=  ec.GetItemValue < string > ( " name " ); // 不区分大小写
/*

//或者使用索引的方式,但必须明确上面OQL表达式Select方法里面属性的顺序 
                e.GroupName = ec.GetItemValue<strng>(2);
                e.ID = ec.GetItemValue<int>(0);
                e.Name = ec.GetItemValue<string>(1);

*/
                
return  e; 
            }
            ).ToList ();
复制代码

  

上面的写法没有LINQ那么完美,人家LINQ是近水楼台先得月,MS自家的苗子,可以依靠“编译器语法糖”来写出优美的LINQ程序,但我们的这个实现从原理上说非常轻巧,在众多非官方的ORM框架中,真正支持了实体类的多表连接查询!

 

有关OQL的多实体连接查询仅在PDF.NET框架V4.1以后版本支持,该功能作为框架的一项重要功能扩展,已经在商业项目中开始使用,感兴趣的朋友可以一起研究。

下面的代码是实际项目中的一段代码,我们来看看完整的调用方式:

 

复制代码
public   string  GetTradeTypeID( string  foundAccount, string  jjdm, string  type)
        {
            
/* 执行下面的查询将使用如下类似的SQL:
             select distinct a.tradetype tradetypeid from wft_customerfundtrade a
                 left join wft_customerfundtradedetails b on a.tradetype =b.tradetypeid
                      where   (a.fundaccount ='1185919705'  and a.jjdm ='KF0003')
                         and ( b.tradetype='定投' or b.tradetype='基金转换的记帐')
             * 
             
*/
            WFT_CustomerFundTrade trade 
=   new  WFT_CustomerFundTrade() { FundAccount  =  foundAccount, JJDM  =  jjdm };
            WFT_CustomerFundTradeDetails detail 
=   new  WFT_CustomerFundTradeDetails() { TradeType  =  type };
            OQLCompare cmpAll 
=   new  OQLCompare(trade, detail);

            OQL q 
=  OQL.From(trade)
                .LeftJoin(detail).On(trade.TradeType, detail.TradeTypeId)
                .Select(trade.TradeType)
                .Where(
                        (cmpAll.Comparer(trade.FundAccount) 
&  cmpAll.Comparer(trade.JJDM))  &
                        (cmpAll.Comparer(detail.TradeType) 
|  cmpAll.Comparer(detail.TradeType,  " = " " 基金转换的记帐 " ))
                )
                .END;

            q.Distinct 
=   true ;

            EntityContainer container 
=   new  EntityContainer(q);
            var result 
=  container.Map < WFT_CustomerFundTrade > ().ToList();
            
if  (result.Count  ==   0 )
                
return   "" ;
            
else
                
return  result[ 0 ].TradeType;
}
复制代码

由这个例子可以看出,PDF.NET的ORM框架中的实体对象查询语言--OQL,已经可以完成很复杂的查询了,包括多实体类关联查询。



    本文转自深蓝医生博客园博客,原文链接:http://www.cnblogs.com/bluedoctor/archive/2011/05/23/2054541.html,如需转载请自行联系原作者



相关文章
|
5月前
|
移动开发 前端开发 HTML5
Twaver-HTML5基础学习(20)数据容器(3)_数据的批量加载(节省性能方法)
本文介绍了Twaver HTML5中数据的批量加载方法,通过使用`box.startBatch()`可以在大量数据加载时提高性能。文章通过示例代码展示了如何在React组件中使用批量加载功能,以减少界面重绘次数并提升效率。
70 2
Twaver-HTML5基础学习(20)数据容器(3)_数据的批量加载(节省性能方法)
|
5月前
|
XML 存储 JSON
Twaver-HTML5基础学习(19)数据容器(2)_数据序列化_XML、Json
本文介绍了Twaver HTML5中的数据序列化,包括XML和JSON格式的序列化与反序列化方法。文章通过示例代码展示了如何将DataBox中的数据序列化为XML和JSON字符串,以及如何从这些字符串中反序列化数据,重建DataBox中的对象。此外,还提到了用户自定义属性的序列化注册方法。
60 1
|
2月前
|
存储 安全 数据中心
Docker 容器凭借轻量级和高效的特性,成为应用部署的重要工具
Docker 容器凭借轻量级和高效的特性,成为应用部署的重要工具。本文探讨了 Docker 如何通过 Namespace 和 Cgroups 实现 CPU、内存、网络和存储资源的隔离,提高系统安全性和资源利用率,以及面临的挑战和应对策略。
64 1
|
5月前
|
XML 移动开发 JSON
Twaver-HTML5基础学习(18)数据容器(1)_增删查改、遍历数据容器、包含网元判断
本文介绍了Twaver HTML5中的数据容器(DataBox),包括如何进行增删查改操作、遍历数据容器以及判断网元是否存在于数据容器中。DataBox用于管理所有的网元对象,如ElementBox、LayerBox、AlarmBox等,并通过示例代码展示了其常用方法的使用。
64 1
Twaver-HTML5基础学习(18)数据容器(1)_增删查改、遍历数据容器、包含网元判断
|
5月前
|
存储 索引 Python
python中的数据容器
python中的数据容器
|
6月前
|
安全 网络安全 数据安全/隐私保护
云原生技术探索:容器化与微服务架构的实践之路网络安全与信息安全:保护数据的关键策略
【8月更文挑战第28天】本文将深入探讨云原生技术的核心概念,包括容器化和微服务架构。我们将通过实际案例和代码示例,展示如何在云平台上实现高效的应用部署和管理。文章不仅提供理论知识,还包含实操指南,帮助开发者理解并应用这些前沿技术。 【8月更文挑战第28天】在数字化时代,网络安全和信息安全是保护个人和企业数据的前线防御。本文将探讨网络安全漏洞的成因、加密技术的应用以及提升安全意识的重要性。文章旨在通过分析网络安全的薄弱环节,介绍如何利用加密技术和提高用户警觉性来构建更为坚固的数据保护屏障。
|
6月前
|
存储 Docker 容器
在Docker中,容器退出后,通过docker ps命令查看不到,数据会丢失么?
在Docker中,容器退出后,通过docker ps命令查看不到,数据会丢失么?
|
6月前
|
监控 安全 网络安全
|
7月前
|
存储 C++ 容器
开发与运维数组问题之C++标准库中提供数据容器作为数组的替代如何解决
开发与运维数组问题之C++标准库中提供数据容器作为数组的替代如何解决
82 5
|
6月前
|
域名解析 Kubernetes 负载均衡
在K8S中,外部访问容器服务,比如说提供了一个域名,链路怎么走?数据经过哪些组件?
在K8S中,外部访问容器服务,比如说提供了一个域名,链路怎么走?数据经过哪些组件?