当前位置: 首页 > news >正文

dotText源码阅读(4)--DTO和数据访问

dotText源码阅读(4)--DTO和数据访问
Dottext中的DTO是一个是怎么实现的呢?这些是作为3层体系的实现内容。DTO的使用很多高人都有自己的看法,争论也不少。不过,我在这里要说的是dottext为什么要用DTO,我理解作者是想通过DTO确保维护3层体系,目的是解耦合各层之间的相互依赖,为各层之间的更新升级预留足够的维护空间。
Dottext.Framework.Data. IDTOProvider 定义了关于DTO的接口,这个接口涉及到的对象机器操作有:
Entry        也就是blog中发表的文章,其实体、对象的声明在Components目录下的Entry.cs中。需要注意的是该类继承了IblogIdentifier 接口,并且声明了[Serializable]属性。几乎定义的实体类型都类似该类。
Links        收藏的链接
Categories        类别,注意blog的系统分类和每一个博客的分类一起存储的,通过-1的blog来区分系统定义的分类。
Stats               统计信息
Configuration     配置类
KeyWords               blog关键字
Images            相册
Archives         文章归档
ScheduledEvents        调度事件
Logger                   日志对象
Rate                点击统计
Security         身份验证
MailNotify        邮件
IblogIdentifier接口是规定了该类必须要有一个归属哪一个blogID的,这容易理解,因为无论是文章还是统计信息、个人连结、收藏、相夹都属于私人的。
除了实体类外,还实现了相应实体类的收集类。对于数据绑定来说,很多人喜欢采用实体收集类来代替DataSet等,我也是这类人。这些实体收集类也标记了[Serializable]属性,也可以利用序列化进行配置
 
关于这些实体类的操作,dottext定义了IDTOProvider的接口,来定义对DTO的操作,具体在Dottext.Framework.Data目录下,这个接口需要其他具体类实现,但是体现了作者的设计思路:就是不把实现根据体的数据层死死捆绑,这个可以为我们借鉴。
 
为了进一步实现自己的思路,dottext还特意夹了一个数据层的抽象,IDbProvider ,此接口实现了对于各个DTC实体的数据访问,但是都是通过定义返回IdataReader和DataSet来实现对于具体数据库的封装。Dottext的作者在书写代码时候,做了大量的分类注释。关于数据层的具体实现,我的这个版本是基于SQL server的,所有具体的数据操作在Data目录下的SqlDataProvider.cs,这个类实现了IdbProvider,但是我们看到的几乎都是存储过程调用,而dottext的Sql版本大约110多个,所以要仔细阅读这些数据层访问细节,会花费很多时间。但是理清了这些头绪,我们可以知道如何去阅读甚至去实现修改了。
 
。那系统是如何实现数据访问的灵活配置呢?这个举一个例子,发表文章的操作,最终的操作是落在admin\ UserControls\ EntryEditor.ascx上(详细分析可能后面会补充),其中的代码如下:
private void UpdatePost()
              {      
                     if(Page.IsValid)
                     {
                            string successMessage = Constants.RES_SUCCESSNEW;
                            try
                            {
                                   Entry entry = new Entry(EntryType);
                                   entry.Title = txbTitle.Text;
                                   ……
                                   entry.BlogID = Config.CurrentBlog(Context).BlogID;
                            if (PostID > 0)
                                   {
                                          successMessage = Constants.RES_SUCCESSEDIT;
                                          entry.DateUpdated = DateTime.Now;                                                                            entry.EntryID = PostID;                                      entry.Link=Dottext.Framework.Configuration.Config.CurrentBlog().UrlFormats.EntryUrl(entry);
                                          if(chkIsMoveTo.Checked)
                                          {
                                                 entry.PostType=entry.PostType^((PostType)3);
                                                
                                          }
                                          Entries.Update(entry);
                                          ……
 
                                   if (PostID > 0)
                                   {
                                          //LinkCollection lc = new LinkCollection();
                                          ArrayList al = new ArrayList();
                                          int count = cklCategories.Items.Count;
                                          if(chkIsMoveTo.Checked)
                                          {
                                                 count=0;
                                          }
                                          //文章分类
                                          for (int i =0; i<count;i++)
                                          {
                                                 if (cklCategories.Items[i].Selected)
                                                 {
                                                        al.Add(Int32.Parse(cklCategories.Items[i].Value));
                                                 }
                                          }
                                          //网站分类
。。。。。。
                            }
                            catch(Exception ex)
                            {                                   this.Messages.ShowError(String.Format(Constants.RES_EXCEPTION,
                                          Constants.RES_FAILUREEDIT, ex.Message));
                            }
                            finally
                            {
                                   Results.Collapsible = false;
                            }
                     }
              }
这里的Entry属于DTO类型,在 Components 下有解释。如果是第一次新发表的文章,那么会执行:
Entries.Update(entry);        
此时会执行:
public static int Create(Entry entry)
         {
              return Create(entry,null);
         }
静态方法,最终调用
public static int Create(Entry entry, int[] CategoryIDs)
         {
              HandlerManager.PreCommit(entry,ProcessAction.Insert);            
              int result = DTOProvider.Instance().Create(entry,CategoryIDs);             
              if(result > 0)
              {
                   HandlerManager.PostCommit(entry,ProcessAction.Insert);                
              }
              return result;
         }
我们主要集中看看
int result = DTOProvider.Instance().Create(entry,CategoryIDs);
该语句执行的需要好好揣摩:
DTOProvider 的声明在providers目录下:
他有一个静态的声明构造函数
static DTOProvider()
         {
              DTOProviderConfiguration dtoPC = Config.Settings.BlogProviders.DTOProvider;
              idto = (IDTOProvider)dtoPC.Instance();
     }
用于在静态调用该类的方法之前执行构造(这里相当于使用了单例模式)。此时会利用前民提到的配置体系获取DTOProvider配置。DTOProviderConfiguration 具 [XmlRoot("DTOProvider")]属性,从<BlogProviders>节获得的XML片断中得到DTOProviderConfiguration,而需要注意这里的DTOProviderConfiguration继承自一个抽象类BaseProvider。
Config.Settings.BlogProviders 通过反序列化得到了具体的BlogProvider类,但是我们仅仅想获取DTOProvider的属性,而在我手中的版本该处的配置是Dottext.Framework.Data.DataDTOProvider(注意该类的实现了IDTOProvider接口)。DTOProviderConfiguration类型实际上是抽象类BaseProvider的具体实现,但是加上了[XmlRoot("DTOProvider")]属性(可以反序列化),这样将得到了一个provider类型。
idto = (IDTOProvider)dtoPC.Instance();
dtoPC.Instance();会调用BaseProvider(注意是抽象类)中的
public object Instance()
       {
              return Activator.CreateInstance(System.Type.GetType(this.ProviderType));
}
大家看到,这又是一个动态产生类型的方法,也是采用了反射原理。该类的属性ProviderType声明是这样的
[XmlAttribute("type")]
       public string ProviderType
       {
              get   {      return _type;       }
              set       { _type = value;      }
}
可以看到,这是从配置文件中读取到的Type值,具体到我察看的工程值是:Dottext.Framework.Data.DataDTOProvider, Dottext.Framework
这样会实例化DataDTOProvider类,而DataDTOProvider实现了IDTOProvider接口。通过这样的“复杂”的过程, DTOProvider静态构造了一个可以访问数据库层的接口(DTOProvider.Instance()语句)IDTOProvider,而IDTOProvider中正好可以实现了接口函数
int Create(Entry entry, int[] CategoryIDs);这里相对于SQL数据层的细节如下(见得到的是实现类DataDTOProvider ):
public int Create(Entry entry, int[] CategoryIDs)
         {
              if(entry.PostType == PostType.PingTrack)
              {
                   return DbProvider.Instance().InsertPingTrackEntry(entry);// DbProvider稍后解释
              }
 
              FormatEntry(ref entry);
 
              if(entry is CategoryEntry)
              {
                   entry.EntryID = DbProvider.Instance().InsertCategoryEntry(((CategoryEntry)entry));
              }
              else
              {
                   entry.EntryID = DbProvider.Instance().InsertEntry(entry);
        
                   if(CategoryIDs != null)
                   {
                        DbProvider.Instance().SetEntryCategoryList(entry.EntryID,CategoryIDs);
                   }
              }
 
              if(entry.EntryID > -1)// && Config.Settings.Tracking.UseTrackingServices)
              {
                   entry.Link = Dottext.Framework.Configuration.Config.CurrentBlog().UrlFormats.EntryUrl(entry);
                   Config.CurrentBlog().LastUpdated = entry.DateCreated;
 
              }
              else
              {
                   //we need to fail here to stop the PostCommits?
                   throw new BlogFailedPostException("Your entry could not be added to the datastore");
              }
 
              return entry.EntryID;
         }
在这里,实现了对于Entry实体的实体化存储操作。其中的 DbProvider又是值得关注的
static DbProvider()
         {
              DbProviderConfiguration dpc = Config.Settings.BlogProviders.DbProvider;
              dp = (IDbProvider)dpc.Instance();
              dp.ConnectionString = dpc.ConnectionString;
         }
看到没有,跟DTOProvider又是一样的静态化构造。通过序列化的到具体的DB存储操作实体对象Dottext.Framework.Data.SqlDataProvider, Dottext.Framework。在创建一个Entry对象的DB操作中有如下代码:
entry.EntryID = DbProvider.Instance().InsertEntry(entry);
SqlDataProvider的 InsertEntry操作细节如下:
public int InsertEntry(Entry entry)
         {
              SqlParameter[] p =
              {
                   SqlHelper.MakeInParam("@Title", SqlDbType.NVarChar,255,entry.Title),
                   SqlHelper.MakeInParam("@TitleUrl", SqlDbType.NVarChar,255,DataHelper.CheckNull(entry.TitleUrl)),
                   SqlHelper.MakeInParam("@Text",SqlDbType.NText,0,entry.Body),
                   SqlHelper.MakeInParam("@SourceUrl",SqlDbType.NVarChar,200,DataHelper.CheckNull(entry.SourceUrl)),
                   SqlHelper.MakeInParam("@PostType",SqlDbType.Int,4,entry.PostType),
                   SqlHelper.MakeInParam("@Author",SqlDbType.NVarChar,50,DataHelper.CheckNull(entry.Author)),
                   SqlHelper.MakeInParam("@Email",SqlDbType.NVarChar,50,DataHelper.CheckNull(entry.Email)),
                   SqlHelper.MakeInParam("@Description",SqlDbType.NVarChar,500,DataHelper.CheckNull(entry.Description)),
                   SqlHelper.MakeInParam("@SourceName",SqlDbType.NVarChar,200,DataHelper.CheckNull(entry.SourceName)),
                   SqlHelper.MakeInParam("@DateAdded",SqlDbType.DateTime,8,entry.DateCreated),
                   SqlHelper.MakeInParam("@PostConfig",SqlDbType.Int,4,entry.PostConfig),
                   SqlHelper.MakeInParam("@ParentID",SqlDbType.Int,4,entry.ParentID),
                   SqlHelper.MakeInParam("@EntryName",SqlDbType.NVarChar,150,DataHelper.CheckNull(entry.EntryName)),
                   BlogIDParam,
                   SqlHelper.MakeOutParam("@ID",SqlDbType.Int,4)
                  
              };
              NonQueryInt("blog_InsertEntry",p);
              return (int)p[14].Value;
         }
看到否,这是一个具体的sql存储过程调用代码。
就这样,利用配置文件我们指定了BlogProviders 的DTOProvider 和DbProvider 具体实例,而根据不同的配置,他们是可以替换成不同的实例,譬如可以将DB层换成Mysql.或者Orcal的具体表操作。
以上阅读,大家需要注意:
1、   静态构造函数
2、 Activator.CreateInstance(System.Type.GetType(this.ProviderType)); 这种利用反射创建对象实例的方法。
另外就是需要理解,dottext采用配置文件来动态指定DTO和DB操作的精巧设计(虽然有些让人懵头)。
 
遗憾的是,我发现博客园的版本似乎有问题,很多操作,他们直接操纵了数据库,这样可能会学让我这种不熟悉源版本的人会产生一定的误解。以上分析,希望能够排除大家的疑问,我可是熬了个通宵哦:)
posted on 2007-07-13 15:24 方正 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/linckle/archive/2007/07/13/817310.html

相关文章:

  • Java之JDBC学习
  • 上海:法制宣传上公交 移动电视受好评
  • 基于FPGA的XPT2046触摸控制器设计
  • Tomcat漏洞利用
  • jQuery获取select中全部option值
  • Dubbo之旅--集群容错和负载均衡
  • 动态权限树控件
  • 南桥-- 算法训练 2的次幂表示
  • 第九章:XML文档集成---AxInternalBase API
  • 微信登陆
  • 文本相似度计算--余弦定理和广义Jaccard系数
  • 结构型模型Bridge
  • PHP实现程序单例执行
  • Visual C#.Net网络程序开发-Tcp篇(3)
  • [New Portal]Windows Azure Virtual Machine (3) 在VM上挂载磁盘
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • ES6之路之模块详解
  • extjs4学习之配置
  • httpie使用详解
  • Java 多线程编程之:notify 和 wait 用法
  • Java小白进阶笔记(3)-初级面向对象
  • Promise面试题,控制异步流程
  • Python_OOP
  • React as a UI Runtime(五、列表)
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 理解 C# 泛型接口中的协变与逆变(抗变)
  • 如何设计一个微型分布式架构?
  • 什么软件可以剪辑音乐?
  • 双管齐下,VMware的容器新战略
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 一道闭包题引发的思考
  • Nginx实现动静分离
  • 国内开源镜像站点
  • ![CDATA[ ]] 是什么东东
  • ###C语言程序设计-----C语言学习(3)#
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • $.ajax中的eval及dataType
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (十一)c52学习之旅-动态数码管
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转)【Hibernate总结系列】使用举例
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .java 9 找不到符号_java找不到符号
  • .Net 4.0并行库实用性演练
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET Core Web APi类库如何内嵌运行?
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .NET Framework 服务实现监控可观测性最佳实践
  • .Net 代码性能 - (1)
  • .NET 分布式技术比较
  • .NET关于 跳过SSL中遇到的问题