一年没写BLOG了,这几天网通的奥运项目初验通过了,暂时可以轻松一下。
今天刚刚写完这个BLOG,又准备让我搞一个解析PD的XML文件的东东,把表结构和数据字典取出来直接配置到数据库的实体属性数据字典系统表中。分享一下:http://blog.csdn.net/flygoldfish
先来看一段代码,想想它是来实现什么的?public class EntityTest:WebMIS.Data.EntityAccess.DBEntity{     private int _ID = -1;     private string _Name = "test";
     public int ID     {         get{return _ID;}         set{_ID=value;}     }     public string Name     {         get{return _Name;}         set{_Name=value;}     }      public EntityTest():base("TableNameOfEntityTest","ID"){}      public override IList GetFields()     {         return new string[]{"ID","Name"};     }      public override IList GetFieldValues()     {         return new object[]{_ID,_Name};     }      public override IList GetPrimaryKeyValues()     {         return new string[]{"ID"};     }      public override void LoadFrom(System.Data.DataRow entityDataRow)     {         _ID = int.Parse(entityDataRow["ID"].ToString());         _Name = entityDataRow["Name"].ToString();     }} public class EntityTestManagement:WebMIS.Data.EntityAccess.EntityAccess{     public EntityTestManagement(EntityTest entity):base(entity){}      protected override WebMIS.Data.EntityAccess.IExeSql DoReturnDataAccessInstance()     {         return null;  //只要实现IExeSql并返回,即可完成跨数据库操作     }}       也许大家看出来了,EntityTest完成一个实体定义,一般来说对应于数据库表的字段。EntityTest继承于WebMIS.Data.EntityAccess.DBEntity,其实是实现了IEntityMap接口。  不写一个SQL语句,不再多写一行程序,就实现数据的增、删、改、查,这就是这样做的目的。 那么,如何达到这个目的呢?  只要把实现了IEntityMap接口的实体对象,作为WebMIS.Data.EntityAccess.EntityAccess的构造函数参数即可达到目的。  为什么会这样?这其它就是总结的结果。  因为我在做数据处时的时候,定义了实体,每个实体操作总是要写Insert、Update、Delete、FillByPK...这类的方法,而且总是会用到表的字段。这样重复做了几次之后,想想是不是应该抽象一下,并把它重构。于是发现了规律性,把Insert、Update、Delete、FillByPK提到基类WebMIS.Data.EntityAccess.EntityAccess中。  提到基类中后,问题又来了,Insert、Update、Delete、FillByPK用到的表、字段它们从何来?于是,将它们抽象出来,定义到接口中,于是IEntityMap接口诞生了,从中可以找到用到的表和字段,于是就可以同它们动态的生成需要的SQL语句,为了防止注入式攻击和非法字符引发错误,于是采用参数形式解释SQL语句。  这样,问题又来了,是不是执行SQL语句的数据库连接数据访问层就在EntityAccess中实现。答案是否定的,原因如下:   1>偶合性     为了让EntityAccess独立,放到哪里就运行到哪你,所以需要把真正招行SQL语句的代码独立出来。   2>跨数据访问     如果写死了,就可能只为一种数据库服务限制死,所以需要把真正招行SQL语句的代码独立出来,这样,谁提供数据执行应适应谁的数据库。于是,定义   IExeSql  接口。

解决方案 »

  1.   

    using System; namespace WebMIS.Data.EntityAccess{     /// <summary>     /// 执行带参的SQL接口,如例如ExecuteSql("Delete From 表1 Where aa=参数1 And bb=参数2",new string[]{"参数1","参数2"},new string[]{"ax","bx"})。     /// </summary>     public interface IExeSql     {         /// <summary>         /// 执行单个带参数的操作型SQL,并返回受影响的行数。         /// 例如ExecuteSql("Delete From 表1 Where aa=参数1 And bb=参数2",new string[]{"参数1","参数2"},new string[]{"ax","bx"})。         /// </summary>         /// <param name="p_strSQL">带参数的SQL</param>         /// <param name="p_strParams">参数列表</param>         /// <param name="p_objValues">参数对应的值</param>         /// <returns>返回受影响的行数,不成功返回-1</returns>         int ExecuteSql(string p_strSQL,System.Collections.IList p_strParams,System.Collections.IList p_objValues);          /// <summary>         /// 执行单个带参数的选择型SQL,并返回它的记录集。         /// 例如CreateDataSet("Select * From 表1 Where aa=参数1 And bb=参数2",new string[]{"参数1","参数2"},new string[]{"ax","bx"})。         /// </summary>         /// <param name="p_strSQL">带参数的SQL</param>         /// <param name="p_strParams">参数列表</param>         /// <param name="p_objValues">参数对应的值</param>          /// <returns>返回受影响的行数,不成功返回-1</returns>         System.Data.DataSet CreateDataSet(string p_strSQL,System.Collections.IList p_strParams,System.Collections.IList p_objValues);      } }//End Namespace
    而只要写一个适配器,原来的数据访问组件即可很好应用于些。using System;
    using WebMIS.Data.DataAccess;
    using WebMIS.Data.EntityAccess;
    using System.Text;namespace SureKam.IBM.DAL
    {
    /// <summary>
    /// 应用适配器模式实现可执行SQL接口,不能实例化。
    /// </summary>
    public sealed class ExecuteSqlAdapter:IExeSql
    {
    //**********单例**********
    private static IDataAccess _DataAccessInstance = null;
    private static ExecuteSqlAdapter _ExecuteSqlAdapterInstance = null; #region 实现单例... private static IDataAccess GetInstanceOfDataAccess()
    {
    if (_DataAccessInstance == null)
    {
    _DataAccessInstance = DefaultDataAccess.GenericDefault;
    } return _DataAccessInstance;
    }

    private static ExecuteSqlAdapter GetInstanceOfExecuteSqlAdapter()
    {
    if (_ExecuteSqlAdapterInstance == null)
    {
    _ExecuteSqlAdapterInstance = new ExecuteSqlAdapter();
    } return _ExecuteSqlAdapterInstance;
    } #endregion

    //什么也不做,用私有限制,则不能实例不能继承
    private ExecuteSqlAdapter()
    {

    } //**********适配(应用IDataAccess)********** /// <summary>
    /// 执行单个带参数的操作型SQL,并返回受影响的行数。
    /// 例如ExecuteSql("Delete From 表1 Where aa=参数1 And bb=参数2",new string[]{"参数1","参数2"},new string[]{"ax","bx"})。
    /// </summary>
    /// <param name="p_strSQL">带参数的SQL</param>
    /// <param name="p_strParams">参数列表</param>
    /// <param name="p_objValues">参数对应的值</param>
    /// <returns>返回受影响的行数,不成功返回-1</returns>
    public int ExecuteSql(string p_strSQL,System.Collections.IList p_strParams,System.Collections.IList p_objValues)
    {
    IDataAccess da = GetInstanceOfDataAccess(); da.Open(); int effect = da.ExecuteSql(p_strSQL,p_strParams,p_objValues); da.Close(); return effect;
    } /// <summary>
    /// 执行单个带参数的选择型SQL,并返回它的记录集。
    /// 例如CreateDataSet("Select * From 表1 Where aa=参数1 And bb=参数2",new string[]{"参数1","参数2"},new string[]{"ax","bx"})。
    /// </summary>
    /// <param name="p_strSQL">带参数的SQL</param>
    /// <param name="p_strParams">参数列表</param>
    /// <param name="p_objValues">参数对应的值</param>
    /// <returns>返回受影响的行数,不成功返回-1</returns>
    public System.Data.DataSet CreateDataSet(string p_strSQL,System.Collections.IList p_strParams,System.Collections.IList p_objValues)
    {
    IDataAccess da = GetInstanceOfDataAccess(); da.Open(); System.Data.DataSet ds = da.CreateDataSet(p_strSQL,System.Data.CommandType.Text,p_strParams,p_objValues); da.Close(); return ds;
    } public static ExecuteSqlAdapter GetInstance()
    {
    return GetInstanceOfExecuteSqlAdapter();
    }
    }//End Class
    }//End Namespace
      

  2.   

    数据访问如何实现?只要实现IDataAccess接口,应用抽象工厂方法,即可实现跨数据访问。
      

  3.   

    flygoldfish(长江支流) 大哥高手啊!很崇拜你,看过你写的打印系统!
      

  4.   

    http://blog.csdn.net/flygoldfish/archive/2007/04/12/1561792.aspx
      

  5.   

    NBear
    用这个解决方案!NBear V3Description:
    A rapid/high performance/distributed/ORM framework based on .NET 2.0. 
    V3 of NBear is a super big re-design based on the experience of V2, which reserves the IoC and Web module of V2 and bring a new ORM (in NBear.Common/NBear.Common.Design and NBear.Data) implementaion. ORM of NBear is very easy to use, you should be able to use it in real development in 10 minutes.License: BSD
    Copyright: 2005-2008 Teddy.CN
    Contact: Teddy (shijie.ma(at)gmail.com)
    Blog: http://teddyma.cnblogs.com
    Download: http://sf.net/projects/nbear
    AcknowledgementThanks alex(http://qpg2006.cnblogs.com) ! 
    The first version of NBear.MQ (NBear.IoC in v2+ enhanced this function much) in NBear V1 refers 
    much of alex's QPG framework. It is also alex's suggestion to create a this kind of component 
    into NBear. Without you, we will never see NBear.MQ.-Folder Structure:src - Full source code of NBear
    dist - Distributed binary dlls of NBear
    lib - Depending dlls of NBear
    cases - Full functional cases based on NBear
    doc - Documents.
    tutorials - Step by Step tutorials
      

  6.   

    http://community.csdn.net/Expert/topic/5169/5169703.xml?temp=.0698511
    多考虑解藕,因为在满足不同需要时,ORM有时是很必要,但对于性能上有要求的框架是否能够满足自动ORM和半ORM.

    public class User
    {
        [Relation(Typeof(UserDetail),RelationType.OneToOne)]
        public UserDetail detail{get;set;}
        .....
    }public class UserDetail
    {
        ....
    }User user=new User(...,new UserDetail(..));
    ISqlSimpleInsertBuilder sqlInsertBuilder=new SqlServerSimpleInsertBuilderSqlBuidler();
    string sqlInsert=sqlInsertBuilder.Parse(user);
    database.Execute(sqlInsert);ISqlSimpleSelectBuilder sqlSelectBuilder=new SqlServerSimpleSelectBuilderSqlBuilder();
    string sqlSelect=sqlSelectBuilder.Parse(ConditionsType.Custom,"User.UserId=UserDetial.UserId And UserDetial.Age>30");
    DataSet ds=database.Select(sqlSelect);
    如果要ORM,在上面架构一层将结果进行映射,对于SqlBuilder有地方不满意完全可以进行重构。//ISqlComplexBuilder sqlBuilder=new SqlServerComplexSqlBuidler();
    //StringCollection sqls=sqlBuilder.InsertParse(user);
      

  7.   

    petshop4。0也对不同数据库进行了封装,不知道有你的好吗?
      

  8.   

    对于Petshop讨论。
    http://community.csdn.net/Expert/topic/5449/5449122.xml?temp=.4689447
      

  9.   

    上面那种封装,对于简单的标准的sql操作还可以
    如果遇到,插入自动编号,oracle 和  sqlservice 就不一样了
    插入后取得主键,在往子表插入的那种操作,很多数据库都不一样。
    这只是很容易碰到的问题。
    如果要兼容全部数据库要满足1) 如果你都是单一表操作而且只用标准sql ,或全部数据库都支持的
    就能基本能完成你的业务。2)数据库的设计,包括字段的类型都是每个数据库通用的
      如: sqlservice 有bool 型,oracle 没有
          Oracle 有数组,sqlservice 没有
      如果你实体类里有bool 的 oracle 取数据的时候就和sqlservice 不一样
      sqlservice 不用强制转化类型直接 (bool) 转化即可
      oracle 就的强制转化一下,而且oracle 的全部数字类型在.net 下都是decmail   
      

  10.   

    认真思考,多做实践。
    IDataBase database=new OracleDataBase(oracleConfig);
    User user=new User(...,new UserDetail(..));
    IDataProvider userProvider=database.GetDataProvider(user);
    userProvider.Insert(user);
    User和UserDetail相应信息插入到Oracle中。
    将来如果碰到不知道的数据库,自己可以根据框架进行实现,无法确定自己的框架(少定接口,多写抽象类,小功能类)到一定时候框架就慢慢浮显上来了。