我做的:1、DataAccess,跨数据访问,专门用于数据存取,已封装
   IDataAccess          数据库打开关闭、执行SQL等
   IDataAccessFactory   工厂,根据配置文件实例多种数据访问,已实现Access、SQLServer、Oracle、DB2、OleDB、ODBC2、EntityAccess,跨数据访问,调用数据访问层,为了与DataAccess实现松耦合,增加了IExeSql接口,因而只要你的数据访问实现了IExeSql接口也行,已封装   IEntityAccess,依赖IEntityFacade,调用IExeSql,是IEntityMap与DB的中间产物,已封装
   IEntityMap,依赖IEntityFacade,调用IEntityAccess的增、删、改查
   IEntityFacade,不用说了,仅仅是对象,这样不像强类型暴露了数据结构这里的命名刚更改为现在这个名,正好和数据访问、中间层、表现层对应3、实体定义与实体管理,实现IEntityFacade、IEntityMap接口或EntityAccess给定的基类
   EntityDefine如PersonEntiy
   例如成员Name,Age,这个名字不一定是数据库中Person表的字段名,这样很好的保护了结构不暴露,UI调用也方便,直接调用person.Name比强类型的dataRow["Name"].ToString()更直接方便,如果用强类型,UI还要了解结构,不爽。
  如果你不会在意像DataSet强类型暴露数据结构,EntityManagement直接继承IEntityFacade的已实现的基本类EntityFacade并实现IEntityMap   EntityManagement如PersonManagement
   调用者自己用成员适配模式定义EntityManagement适配IEntityMap的增删改查,这样就不会暴露数据结构
  如果你不会在意像DataSet强类型暴露数据结构,EntityManagement直接继承IEntityMap或它的基本实现EntityMap类
4、还有业务外观和业务逻辑,调用EntityManagement,至于逻辑如多个实体对象利用COM+达到事务共享  因为各个对象在不同的数据访问层中提交,但很多时候需要事务,这里启动MSDTS5、用户界面层,直接申明实体如PersonEntiy并用EntityManagement如PersonManagement达到数据存取目的。PersonEntiy仅仅是根据成员读写数据,调用PersonManagement的增删改
这样,UI不像调用强类型的DataSet还要清楚字段名等,而直接以对象方式存取,屏蔽了数据结构。需要说明的是:
只要实现EntityAccess的IEntityMap接口,数据存取不用你写一行SQL,自动跨数据访问。代码如下:现在为简单起签,将实体定义直接包含实与数据映射需要看演示的朋友可以临时加QQ群(网友建)
群号:17556475您下载代码后可以主动退出群。
需要说明的是把示例代码上传到群上的时候还是采用以前的命名方法,但是也是这个思想,你只需更改配置文件(见readme.txt)无需更改代码就可以运行在Access、SQLServer、Oracle上。最后更新代码将在我的Blog上下载,并再加以文章说明。http://blog.csdn.net/flygoldfish

解决方案 »

  1.   

    /// <summary>
    /// 定义客户资料管理之客户对象数据。
    /// </summary>
    public class Product:EntityObjectBase
    {
    private long _ProductID;
    private string _ProductName;
    private int _SupplierID;
    private int _CategoryID;
    ...
    #region 属性.../// <summary>
    /// 获取或设置产品ID。
    /// </summary>
    public long ProductID
    {
    get
    {
    return _ProductID;
    }
    set
    {
    _ProductID = value;
    }
    }
    ...
    #endregion 属性.../// <summary>
    /// 创建对象新的实例。
    /// </summary>
    public Product():base("Products","ProductID")
    {
    }public override IList GetFields()
    {
    string[] arrFields = new string[]{
    "ProductID",
    "ProductName",
    ... }; return arrFields;
    }public override IList GetFieldValues()
    {
    object[] arrFieldValues = new object[]{
    _ProductID,
    _ProductName,
    ... }; return arrFieldValues;
    }public override IList GetPrimaryKeyValues()
    {
    return new long[]{_ProductID};
    }public override void LoadFrom(System.Data.DataRow entityDataRow)
    {
    _ProductID = long.Parse(entityDataRow["ProductID"].ToString());
    _ProductName = entityDataRow["ProductName"].ToString();
    ...
    }
    }
      

  2.   

    /// <summary>
    /// 定义客户资料管理之客户对象数据。
    /// </summary>
    public class Product:EntityObjectBase
    {
    private long _ProductID;
    private string _ProductName;
    private int _SupplierID;
    private int _CategoryID;
    private string _QuantityPerUnit = "无";
    private float _UnitPrice;
    private int _UnitsInStock;
    private int _UnitsOnOrder;
    private int _ReorderLevel;
    private bool _Discontinued;#region 属性.../// <summary>
    /// 获取或设置产品ID。
    /// </summary>
    public long ProductID
    {
    get
    {
    return _ProductID;
    }
    set
    {
    _ProductID = value;
    }
    }/// <summary>
    /// 获取或设置产品名称。
    /// </summary>
    public string ProductName
    {
    get
    {
    return _ProductName;
    }
    set
    {
    _ProductName = value;
    }
    }/// <summary>
    /// 获取或设置供应商ID。
    /// </summary>
    public int SupplierID
    {
    get
    {
    return _SupplierID;
    }
    set
    {
    _SupplierID = value;
    }
    }/// <summary>
    /// 获取或设置类别ID。
    /// </summary>
    public int CategoryID
    {
    get
    {
    return _CategoryID;
    }
    set
    {
    _CategoryID = value;
    }
    }/// <summary>
    /// 获取或设置单位数量。
    /// </summary>
    public string QuantityPerUnit
    {
    get
    {
    return _QuantityPerUnit;
    }
    set
    {
    _QuantityPerUnit = value;
    }
    }/// <summary>
    /// 获取或设置单价。
    /// </summary>
    public float UnitPrice
    {
    get
    {
    return _UnitPrice;
    }
    set
    {
    _UnitPrice = value;
    }
    }/// <summary>
    /// 获取或设置库存量。
    /// </summary>
    public int UnitsInStock
    {
    get
    {
    return _UnitsInStock;
    }
    set
    {
    _UnitsInStock = value;
    }
    }/// <summary>
    /// 获取或设置订购量。
    /// </summary>
    public int UnitsOnOrder
    {
    get
    {
    return _UnitsOnOrder;
    }
    set
    {
    _UnitsOnOrder = value;
    }
    }/// <summary>
    /// 获取或设置再订购量。
    /// </summary>
    public int ReorderLevel
    {
    get
    {
    return _ReorderLevel;
    }
    set
    {
    _ReorderLevel = value;
    }
    }/// <summary>
    /// 获取或设置中止标识。
    /// </summary>
    public bool Discontinued
    {
    get
    {
    return _Discontinued;
    }
    set
    {
    _Discontinued = value;
    }
    }#endregion 属性.../// <summary>
    /// 创建对象新的实例。
    /// </summary>
    public Product():base("Products","ProductID")
    {
    }public override IList GetFields()
    {
    string[] arrFields = new string[]{
    "ProductID",
    "ProductName",
    "SupplierID",
    "CategoryID",
    "QuantityPerUnit",
    "UnitPrice",
    "UnitsInStock",
    "UnitsOnOrder",
    "ReorderLevel",
    "Discontinued"
    }; return arrFields;
    }public override IList GetFieldValues()
    {
    object[] arrFieldValues = new object[]{
    _ProductID,
    _ProductName,
    _SupplierID,
    _CategoryID,
    _QuantityPerUnit,
    _UnitPrice,
    _UnitsInStock,
    _UnitsOnOrder,
    _ReorderLevel,
    _Discontinued
    }; return arrFieldValues;
    }public override IList GetPrimaryKeyValues()
    {
    return new long[]{_ProductID};
    }public override void LoadFrom(System.Data.DataRow entityDataRow)
    {
    _ProductID = long.Parse(entityDataRow["ProductID"].ToString());
    _ProductName = entityDataRow["ProductName"].ToString();
    _SupplierID = int.Parse(entityDataRow["SupplierID"].ToString());
    _CategoryID = int.Parse(entityDataRow["CategoryID"].ToString());
    _QuantityPerUnit = entityDataRow["QuantityPerUnit"].ToString();
    //金额型为decimal
    _UnitPrice = float.Parse(entityDataRow["UnitPrice"].ToString()); _UnitsInStock = int.Parse(entityDataRow["UnitsInStock"].ToString());
    _UnitsOnOrder = int.Parse(entityDataRow["UnitsOnOrder"].ToString());
    _ReorderLevel = int.Parse(entityDataRow["ReorderLevel"].ToString()); //bit、是否字段为布尔型,Oracle里没
    //_Discontinued = bool.Parse(entityDataRow["Discontinued"].ToString());
    if (entityDataRow["Discontinued"].ToString().ToUpper() == "1" || entityDataRow["Discontinued"].ToString().ToUpper() == "TRUE")
    {
    _Discontinued = true;
    }
    else
    {
    _Discontinued = false;
    }}
    }代码就这么多,即可实现跨数据存取
      

  3.   

    晕了,二楼贴错了using System;using WebMIS.Data.EntityAccess;//using WebMIS.COM.CN.BEL;
    using WebMIS.COM.CN.Business.Entity;
    using WebMIS.COM.CN.DAL;namespace WebMIS.COM.CN.Business.EntityManagement
    {
    /// <summary>
    /// 对产品的增、删、改等管理。
    /// </summary>
    public sealed class ProductManagement:EntityObjectManagementBase
    {
    public ProductManagement()
    {

    } public ProductManagement(Product product):base(product)
    {
    } protected override IExeSql DoReturnDataAccessInstance()
    {
    return ExecuteSqlAdapter.GetInstance();
    } public long GetMaxNextID()
    {
    return WebMIS.COM.CN.DAL.Util.GetMaxNextID(this.Entity.TableName,this.Entity.PrimaryKeys[0].ToString());
    } }
    }
      

  4.   

    http://www.idotnet.org/#sid.25/page.1/
      

  5.   

    其实你这个不能算数据访问层,NHibernate也不是数据访问层。数据访问层要隐藏不同数据库之间的差异,你允许直接执行SQL语句其实等于没有隐藏数据库的差异,另外使用MSDTS也局限数据库的环境。最后问一句,会有几次整体更换数据库的机会,你这顶多算协助简化代码的数据访问帮助器,而并不是数据层,事实上,数据层并不一定是必须的,也不一定要先完成,也可以以后分化出来。
      

  6.   

    这么长一段,没精力看完。
    小心地问一句,你的东西同微软的EnterpriseLibrary有区别吗?
      

  7.   

    TO:Ivony() 
    我这里执行的SQL是由EntiyAccess里的工具自动生成的带参SQL,然后调用DataAccess,由它来处理不同数据库之间的差异。为了不与DataAccess偶合,所以加了一个IExcSQL接口,哈哈,这样两个dll就不至于在一块了。
    说到跨数据库,项目是没有必要的,而做产品型的公司可能会用到。
    再就是如果你是一个组件,可能会被 多家公司采用,那么这几家公司可能采用的不同数据库,而它却帮助了简化。说到多层,其它很多项目也没有必要分多层,特别是小的项目对付着的,能运行交付项目就行了,怎么快怎么来,很多软件公司也不考虑可维护性了。
    不能奢望保证现在软件公司还能生存两生年,所以他们也不会去买组件也不会去采取多层设计:)但是作为程序员,建议大家不要个webform/winform都显示的申明SqlConnection/OracleConnection之类什么的,特别是一些刚做程序的朋友,先不说跨数据库的移植了,把它们专门二次封装一次对自己使用也方便。我这里只是说的实现原理与方式 ,大家可以探讨一下。
    -----------------------------------------------------------------数据访问层要隐藏不同数据库之间的差异,你允许直接执行SQL语句其实等于没有隐藏数据库的差异,另外使用MSDTS也局限数据库的环境。最后问一句,会有几次整体更换数据库的机会,你这顶多算协助简化代码的数据访问帮助器,而并不是数据层,事实上,数据层并不一定是必须的,也不一定要先完成,也可以以后分化出来。
      

  8.   

    TO:liuhui810(小苹果)
    看了设计模式,一个工厂模式就搞定了
      

  9.   

    再TO:liuhui810(小苹果)大家可以到网上看一看 孙亚民 的文章与他设计的架构,他的架构很不错。实体是继承于DataSet,实体定义是用XML描述的,并说明了Java EntityBean优缺点于是进行改进。但是我觉得最大的弱点就是UI调用实体读写数据的时候,先不说数据结构暴露,但总是要dataRow["字段名"]就感觉不爽。
      

  10.   

    之前我也用XML搞过,但是没有孙亚民那样定义的细
    我用XML实际上定义的是Web/Win表单与数据存取之间的关系,也就是说只要你定义了这个XML
    你不用写程序我就可以把Web/Win表单提交到数据库如有兴趣可以一起探讨,在17556475群共享中,有三层示例和我说的 Web/Win表单通用数据存取
      

  11.   

    LZ.发我一份.下不了..谢谢..邮箱  [email protected]
      

  12.   

    写错了邮箱......郁闷..是[email protected]
      

  13.   

    楼上不要留邮箱,在17556475群共享中下,下不了的等两天我在Blog上提供下载。
    http://blog.csdn.net/flygoldfish
      

  14.   

    建议放到blog上,这样看的好累~~
      

  15.   

    会放Blog上的,这两天忙。就是因为这个贴,QQ群“爆”了
      

  16.   

    有两个问题:
    1 对数据库的所有操作都可以通过你这个封装实现么?比如说多表级关联查询?
    2 跨数据库支持,我自定义Sql语句的话,使用Oracle中独有的函数,你切换成Sql Server连接的时候能够自动转换函数实现么?如果以上,你都不能实现,那封装有何用?就拿出来骗骗小孩子么?
      

  17.   

    还有一点需要说明,你口口声声说为了避免数据库报露,可以声明别名,那我问你,谁的数据库不是报露的?Sql Server还是Oracle?难道你只是不报露给你的程序员么?不允许他们用数据库工具直接访问数据库以察看测试数据?简直可笑,对于国内,金蝶和用友的产品够不够大,他们所拥有的高端技术人员水平高与不高,是否在你之上?那你又来告诉我,为什么他们的数据库为何要报露在外,如果不报露的话,应该达到即使我使用SqlServer或者Oracle数据访问工具,也不让我察看到数据库,否则何为不报露?
      

  18.   

    同意lovebingye(降龙) 
    你认为这样做就可以了只能说明你对不同数据库的特性根本不了解。
      

  19.   

    什么都不能一刀切,任何事物都是相对的。暴露只是相对于你给别人提供接口而保护自己数据结构的。例如银行给你一个接口,我就不相信他把表名字段名都给使用者了。对于一般的应用,直接用个datatable绑定算了,哪管那么多,怎么方便怎么实现。不要说用友金碟的数据库了,他是为了应用。用友除了自己开发产品外,产品的服务给了很多人去做,他当然愿意把数据库公开了,对他也没什么影响。暴露不暴露是根据应用和安全的需要,不是楼上说公司大了,把数据库公开才去暴露,这是两个概念。我的观点是怎么方便怎么用,该考虑的时候就考虑。
      

  20.   

    就如很热闹的讨论存储过程是天使还是魔鬼?如果做项目,例如我们给网通做的项目,人家用Oracle,你就不用考虑跨数据库的问题,为了提高效率,该用存储的时候就用。
    但是有些是做产品的,或者组件是为各种人服务的,跨数据访问不得不考虑,尽量不用或少用存储,那些特性的函数也少用。总之,用就意味着多写代码,少用或不用就意味着失去效率。正如以时间换空间与以空间换时间一样,鱼与熊掌不可兼得。
      

  21.   

    CSDN是来讨论技术的,而不是比较技术的。
    可以提出合理与不合理的改进方便,这样才是初衷。
      

  22.   

    冒泡。~~~略看了一下,简单说几句。1. 代码很乱。
    2. 代码复用性差,尤其是datatier 和 UI 。
    3. DataTier 里除了sqlconnection ,剩下全是oledb, 为什么不用专用驱动连接器呢?
    4. 业务写在什么地方?很乱。
    。。楼主还需要继续努力,做好的架构还有距离。
    不要拍砖~~
      

  23.   

    flygoldfish(长江支流) 的,俺顶下,要给分哦 ^6^
      

  24.   

    实体和实体管理实际没几行代码,复杂的事情交给了EntityAccess和DataAccess。
    演示工程有说明,而且还有业务逻辑的目录,只为演示说明这个道理,因而UI没有更抽像。说DataTier 里除了sqlconnection ,剩下全是oledb, 为什么不用专用驱动连接器呢?
    这只能说明你没看,应该是Oracle、Sql、OleDB、ODBC专用的,应用工厂模式。
      

  25.   

    以前我也弄过一个类似于楼主的一个架构。但后来发现这样做的不足也是很多的,所以现在也干脆使用NHibernate了,其实也和XML一样,当参与多个团队时,使用标准化的一些技术和代码有利于开发和维护。随便举几个:
    1.只适用于简单的单表操作,复杂的处理仍然需要再写sql语句,比如跨表;
    2.无法反映一对多,对对多的这种父子关系,也即并没有实现完全的对象化;
    3.数据库字段名修改后需要修改代码并重新编译(这一点当然也可以改进实现);
    4.楼主并没有考虑null情况下的默认值和转换异常;
    5.简单的单数据库完全没有必要使用COM+,在你的架构中通过一些技巧就可以简单传递Transaction;
    6.自动生成Sql语句会花费一定时间,不知道楼主有没有做过优化;
    7.你的架构中,其实没有实现实体字段变更后的标志,所以每次都是全部的字段参与Sql构造,其实并不用,只需要更新更改后的字段即可;
    8.多个记录的集合不知楼主如何处理的,如果用DataSet自然容易;其实于第2点有点类似,如果你真的实现了非常接近强类型DataSet的特性,那2和8的问题也不大,但仍然要考虑的是LazyLoad和数据关系同步,以及数据库操作的缓存和优化
    暂时想到这么多,没仔细看过楼主的代码,有错误的地方还请指正
      

  26.   

    TO:pray1997(pray1997) 非常佩服你的做事的态度。把这个思路放在讨论优缺点及改进这才是初衷。
    做程序讲究的是思路,写程序写的就是思想。我做这个其实只是为了方便自己,老实说,不太考虑性能问题,最主要是为了方便开发和维护。
    我还有一个用XML做表单与数据库映射的,可以解决多表问题和数据库字段改后无需编译,维护也比较方便,同一个类也是应用工厂模式适用于webForm和WinForm。
      

  27.   

    联合主键是这样处理的。主键用的是IList,只要实现这个接口即可处理,一般的情况下。
    在本贴的第一楼是public Product():base("Products","ProductID")
    {
    }public override IList GetPrimaryKeyValues()
    {
    return new long[]{_ProductID};
    },如果是多个字段给成主键public Product():base("Products",new string[]{"字段A","字段B"...})
    {
    }public override IList GetPrimaryKeyValues()
    {
    ArrayList arrlist = new ArrayList();
    arrlist.Add(此时字段A值 );
    arrlist.Add(此时字段A值 );
    return arrlist;
    }
      

  28.   


    1.只适用于简单的单表操作,复杂的处理仍然需要再写sql语句,比如跨表;
    是的,可以override实体管理类的增、删、改操作2.无法反映一对多,对对多的这种父子关系,也即并没有实现完全的对象化;
    提供了一个实体集合,把它作为实体的一个成员,实现一对多3.数据库字段名修改后需要修改代码并重新编译(这一点当然也可以改进实现);
    已有XML映射表单与数据库,些演示代码中没有,在群的另一演示中4.楼主并没有考虑null情况下的默认值和转换异常;
    在演示中确实是这样的,在我的实际项目中有处理
    public override IList GetFieldValues()
    {
      object[] arrFieldValues = new object[]{   _ID, ...
    } GetValidID(kehu_id),
    private object GetValidID(long id)
    { if (id == 0 || id == -1)
    {
    return null;
    }
    return id;
    }在加载的时候作为判断if (entityDataRow["kehu_id"] != DBNull.Value)
    {
    _kehu_id = long.Parse(entityDataRow["kehu_id"].ToString());
    }仅以此为例5.简单的单数据库完全没有必要使用COM+,在你的架构中通过一些技巧就可以简单传递Transaction;
    是的,在一些情况下如GIS采用一个平台,现有系统又是一平台,两事务无法传递,些时采用6.自动生成Sql语句会花费一定时间,不知道楼主有没有做过优化;
    自动生成Sql语句采用的是循环增加参数,采用参数化SQL,如Insert Into 表(字段a,字段b) Values (参数_字段a,参数_字段b),由IExeSql执行。拼SQL用的时间可能忽略不计,主要性能看IExeSql的实现者7.你的架构中,其实没有实现实体字段变更后的标志,所以每次都是全部的字段参与Sql构造,其实并不用,只需要更新更改后的字段即可;
    确实如此8.多个记录的集合不知楼主如何处理的,如果用DataSet自然容易;其实于第2点有点类似,如果你真的实现了非常接近强类型DataSet的特性,那2和8的问题也不大,但仍然要考虑的是LazyLoad和数据关系同步,以及数据库操作的缓存和优化
    提供的是实体数据存取,多个记录需要写在逻辑层中,应用循环调用每实体操作我这个只是实现行数据入口,还有表数据入口实现多记录,表入口很像孙亚民的Entiyt:DataSet。最后,谢谢大家讨论,特别谢谢pray1997(pray1997) 。
      

  29.   

    flygoldfish(长江支流) 说的是websharp吧!
    我也看过websharp,感觉你说的对属性什么的读写不太方便的问题并不存在吧!
    在websharp1.1版本中,实体类是抽象类,虽然是抽象类,但对实体的操作与普通相同啊!反过来说,如果实体类不映身到数据结构,也就是数据结构暴露,那么实体映射些什么呢?上述仅代表个人意见,欢迎拍砖..
      

  30.   

    TO:linfuguo(林子)
    我不是说的websharp,我也没见过和用过。
    我说的是以孙亚民的实体继承于DataSet的例子。
    用DataSet作为各个层数据传输的载体确实是个好的方法,MS的经典示例也是用它。
    这样,UI调用 它的时候,如果存取数据,免不了要dataRow["字段或别名"]
    这样没有person.Name直接。实体类不映身到数据结构,也就是数据结构暴露,那么实体映射些什么呢?
    实体类只定义实体的成员,如字段名叫ID,你可能定义实体的属性字段为“PersonID”。映射我是专门定义在EntityMap中的,可能是类实现,也可能是XML实现。如果你仅仅是项目自己用,不考虑对三方提供接口,实体映射可以定义在实体中。我的示例就是这种情况,并不是非要不暴露:)
    再强调一下,孙亚民的那个架构确实非常好。
      

  31.   

    谢谢!flygoldfish(长江支流)谢谢
      

  32.   

    终于在楼上的问话下,用baidu搜了出来。http://sunnyym.cnblogs.com/Files/sunnyym/构建面向对象的应用软件系统框架.doc
      

  33.   

    原来上上楼有个兄弟说的websharp就是孙亚民的这个东东,偶实在不知道是这个名字,但以前看他的文章的时候也没有提到这个,只是说他们的一个中间件用的就是这种框架。哈哈,在这为孙亚民做了下广告。如果你熟悉或听说过 卢彦 ,请看看他们的AF架构,好像是开源的。
    我还没看过,单凭卢彦认真和挚着,推荐一下。
    http://www.agilelabs.cn
      

  34.   

    欢迎光监点石成金网 http://www.boxigroup.com 网站提供web开发(j2ee .net asp php javascript、c#等) c/s开发(delphi、vb、vc、pb、cb等) 数据库开发(oracle、sqlserver、db2、access、mysql、Postgresql、informix)等学习资料,希望能为你解决燃眉之急 ,请把本网站加入收藏夹,以备不时查询之需 bs+cs讨论群(9638134)
      

  35.   

    我就提一个问题啊,楼主的这个架构对于分页是如何实现的?
    如果在WEB或者是WIN下,分页机制是否一样?
    还有,楼主的这个架构有业务外观层吗?即BusinessFacaed层(DUWAMISH例子中)。目前我们的项目下BusinessFacaed层采用是WEBSERVICE,可以这个WEBSERVICE与分页碰到一起后,遇到了很大的问题,不好解决。
    另外:楼主一定看过微软的EnterpriseLibrary吧,里面就有一个隔离各个数据库的层的例子,其实就是原来的SQLHELP的改进。还有楼主说的孙亚民的那个,其实可以参考VS2005下的强类型数据集的概念!微软其实在VS2005中给我们提供了一个类似于ORM的工具,不过要用好才行。
    AF的架构我看过,我没看懂!还没有弄明白依赖注入等一些概念!
    不过楼主的精神可嘉,我就没有心思写这些东西。