6KBBS门户站长频道业界新闻网站运营网络编程站长资源社区论坛
当前位置: 6kbbs V8.0 官方论坛 » 网络编程 » .NET业务框架开发实战之四 后篇
.NET业务框架开发实战之四 后篇

.NET业务框架开发实战之四 中篇—— 业务层初步构想

前言:

本篇主要讲述如何把DAL和BLL衔接起来。

本篇议题如下:

1).DAL和BLL之前的Mapping

2)。如何Mapping

3)。再次构思

1.DAL和BLL之前的Mapping

首先,业务类和数据实体类不是一 一对应的关系,换句话说,不是一个业务类就一定对应数据库中的一张表。业务类是用只是使用数据实体中的数据而已,所以一个业务类中的数据往往来自多个数据实体。

每个业务类都是有自己的一些属性的,把数据以数据实体或者DataTable的形式从DAL获取之后,BLL类就使用这些数据,BLL不会把这些原生的数据实体暴露给UI。BLL类会把UI中要是用的数据装入到自己的属性中。

所以在这个过程中就有一个赋值的过程,或者称为mapping映射。当Richard提出这个想法后,项目组的同事就问他:为什么要做的这么复杂,还要一 一 的赋值,为什么不直接把数据实体给UI使用,为什么一定要在中间这么转一下呢?

Richard分析了一些原因:

1. 如果直接把数据实体给了UI,那么UI那端就很清楚DAL了,以后数据访问方式从ADO.NET 到了EF,那么UI 就动了,又回到以前了。

2.在BLL中可以对从DAL取出来的数据进行一些处理,如转换格式,计算,组合等。

Richard想到把BLL和DAL彻底的解耦:业务类中不存在数据实体类的引用。这样设计之后灵活性就很大了。最后达到的效果就是:通过配置,配置业务类每个属性的数据的来源。而这个业务类完全不知道这些数据到底来源于哪个或者哪些数据实体。

这样确实很灵活,Richard兴奋不已。

2. 如何Mapping

初步想法通过配置文件。如现在有一个Product的业务类,定义如下:

代码

public class ProductBL
    {

        public string ProductName { get; set; }

        public decimal Price { get; set; }

        public string Description { get; set; }       

    }

那么如何给这些属性赋值,同时也不引用数据实体。Richard用配置文件来实现的,这里Richard就约定了:配置文件的名字就是“业务类的名字”+“Mapping.xml”。所以Product的配置文件就是ProductBLMapping.xml

代码

 



 
 
 

然后再运行的时候就通过反射来赋值。

现在问题又来了:

1).每次都是通过反射来赋值,性能很成问题。

2).如果配置文件出错,调试很不方便。

3).如何处理一个业务类对应对个数据实体的情况,如:

代码 

public class ProductBL
    {
        public string ProductName { get; set; }
        public decimal Price { get; set; }
        public string Description { get; set; }

        //来自CustomDAL
        public string CustomerName { get; set; }

    }

但是好处很明显:

1).DAL和BLL解耦

2).很便于查询对象的实现。例如:在UI代码写:

ICriteria condition=CriteriaFactory.Create(typeof(ProductBL).Where("ProductName", Operation.Equal,"book");

当然ProductName是业务类ProductBL的属性,在查询对象最后解析为SQL语句的时候就可以利用ProductBLMapping.xml来生成SQL。

(注:小洋请大家想想,上面的思想来自于.NET中哪个开源框架?)

对于性能方面,Richard尝试这样解决:

在第一次Mapping的时候,就把这些mapping的信息保存在静态字典中,下次在mapping的时候,就不用再读配置文件了,而且读内存中的字典。

但是这样,随着业务类的增加,内存使用也加大,而且赋值方式还是反射。

3. 再次构思

Richard接着考虑:如何处理一个业务类对应对个数据实体的情况?于是配置文件就改为了:

代码



 
 
 
   

基本的问题算是解决了,但是性能的问题依然存在。

Richard又开始考虑更加好的方式。

本篇就写到这里,谢谢各位。

下篇: .NET 业务框架开发实战之八 业务层Mapping的选择策略版权为小洋和博客园所有,转载请标明出处给作者。

http://www.cnblogs.com/yanyangtian

转载:http://www.cnblogs.com/yanyangtian/archive/2010/06/07/1752921.html

.NET 业务框架开发实战之四 后篇——业务层Mapping的选择策略

前言:

在上一篇文章中提到了mapping,感觉很像在重新实现NHibernate。其实文章的本意是想反映出Richard在思考的时候的一些选择:利用现有的,还是最后自己用别的方式实现。如果一上来就说什么什么好,那太武断了,也很片面,系列文章反复的在强调一点:技术有它的适用场景,没有完美的技术。很多的朋友说本系列在近似的开发一个ORM,其实不是:ORM就是把数据库表转为数据实体,但是本篇中是使用已经转换后的数据实体。是把数据实体的数据给业务类。

而且本篇讨论业务类中的mapping,也就是数据的获取方式,当然,业务类的设计远远不止这些。

开始之前希望在这下面的两点上达到共识:

1).  最好不要把DAL的数据实体(Linq或者Entity Framework生成的),或者原生的DataTable暴露给UI那边(除非一定要,或者有特殊的原因)。

2).  UI使用的是BLL类(或者基于消息的Scheme格式)。

今天的议题如下:

1).第二种Mapping方法。

2).第三种Mapping方法。

1. 第二种Mapping方法。

Richard思考了配置文件的方式,诚然用配置文件确实灵活,但是灵活也是有代价的,因为Framework最后还得公司的开发人员使用,过多的配置和过高的学习成本使得Framework失去了很大的意义。

Richard开始思考了,想到了还有一种最简单的mapping的方式:就是直接一个个的赋值,如:

代码 

public class ProductBL
       {
         public string ProductName { get; set; }
         public decimal Price { get; set; }
         public string Description { get; set; }

         public void Mapping(m_Product productEntity)
         {
            this.ProductName = productEntity.Name;
            this.Price = productEntity.Price;
            this.Description = productEntity.Description;
         }
        }

很明显,这个过程很简单却很繁琐。

和之前使用配置文件的方式相比:

优点:

1). 便于使用和理解

2). 便于调试

缺点:

1). 和数据实体耦合的很紧(其实这不算是缺点,这是和之前配置文件的方式比较而言认为缺点)。上面的代码中就直接使用了m_Product.(大家可以参看之前一篇文章中用配置文件的优缺点)

2). 编写的过程很繁琐。全部是手动的mapping。而且还有关键的一点就是:查询对象怎么生成最终的SQL语句?

例如,下面的代码:

ICriteria condition=CriteriaFactory.Create(typeof(ProductBL).

Where("ProductName", Operation.Equal,"book");

如果采用配置文件的mapping方式,很清楚:在配置文件中ProductBL的ProductName对应m_Product实体的Name字段,也就是对应数据库表m_Product的Name字段(因为在BLL中使用的是通过linq或者Entity Framework生成的m_Product实体)。上面的查询对象最后生成类似select * from m_Product where Name=’book’的语句。

Richard想到NHibernate的实现:在NHibernate也有查询对象,在NHibernate中的查询对象的实现也是依赖NHibernate的那个mapping的配置文件的。

并不是说没有查询对象就不行,不用查询对象,用Linq和Entity Framework也是可以实现的。但是数据层就没有“以不变应万变”了的效果,而且开发人员要掌握各种的数据访问技术:ADO.NET, Linq等。(可以参看.NET 分布式架构开发实战之三 数据访问深入一点的思考一文)。

现在Richard面临的问题就是:

1)。 不用配置文件mapping,这样查询对象就不好实现。

2)。 手动的敲入代码mapping,重复的劳动。

Richard思考是否更好的方式解决上面的问题。于是第三种方式就产生了。

3. 第三种Mapping方法。

第三种mapping的方法就是综合了之前两种mapping的优点,而避开了他们的缺点。

Richard想到解决手动mapping的方法就是:图形化的代码生成来代替手写代码。而且要想办法保存数据库字段的一些信息。

很巧的就是:linq和EF生成的实体中的字段信息就反映了数据表字段的信息。这点可以利用起来。下面的草图是用Visio画出的,代表了Richard的想法。其实Richard也没有一下就开发出下面的工具,一切还是处于设计阶段。

Richard设计出了自动生成代码的工具(工具的开发Richard思考过了,可以采用最简单的实现方式:一个Windows程序。也想过用DSL工具开发,但是DSL得学习过程还是有点复杂的)。

注:虽然说是代码生成工具,其实一开始Richard也是想的很简单:就是一个写文本的操作。

在上面的界面中,选择要和哪个数据实体类mapping,可以通过选择“MappingName”来实现。然后点击“Properties”按钮,出现了如下的界面:

这是一个专门用来配置mapping的界面:点击“Add”按钮,添加一个业务类的属性,然后用”MappingTo”来设置这个属性的数据从数据实体类的那个字段中获取。在选择数据实体字段的时候,也把这个选中数据实体的字段信息保存起来,供给之后的查询对象使用。

基本思路Richard已经有了。现在的问题就是把上面选选中数据字段信息保存在哪里,而且还得和业务类的属性对应,例如,Id对应业务类Product的ProductId,而不是其他的属性。

在mapping的时候,一般是在业务类中定义一个属性,然后赋值:

public string ProductId { get; set; }
this.ProductName = productEntity.Id;

为了保存数据实体字段的信息,业务类的属性声明就改为下面了:

代码

public static readonly PropertyInfo ProductIdProperty = RegisterProperty(
      typeof(Product),
      new PropertyInfo("ProductId",typeof(M_Product)","Id"));

    public string ProductId
    {
      get { return ReadProperty(ProductIdProperty); }
      set { LoadProperty(ProductIdProperty, value); }
    }

上面的代码通过生成的方式就比较方便,而且上面的属性声明还有更多其他的用途。初一看和WPF中依赖属性很像,确实思路也是从WPF借鉴而来的。这里简称“Mapping属性”。

就写到这里,真是对不住大家,因为本篇写的比较的啰嗦,而且还没有写完。

下篇讲述Mapping属性的实现原理和原因,就是为什么要是用ProductIdProperty那种声明方式。

版权为小洋和博客园所有,欢迎转载,转载请标明出处给作者。 http://www.cnblogs.com/yanyangtian

转载:http://www.cnblogs.com/yanyangtian/archive/2010/06/09/1754426.html

推荐资讯
热文排行