echeng192(阿飞(想要飞却又飞不高)) :
 所说不错,我自己写过,但总觉得差强我意,这个类不好写。

解决方案 »

  1.   

    微软的mspetshop我也仔细研究过,每个表都有具体的实体层和数据访问层。
      

  2.   

    以前CSDN上有几遍孙亚民的文章。
    他写的通用类是用到XML文件做为每个对象的配置文件,这是个比较好的思路。
      

  3.   

    希望大家不要泛泛而谈,继承啊,接口啊的。
    echeng192(阿飞(想要飞却又飞不高)) 你是否有孙亚民的文档给看看。
      

  4.   

    我有一个基类,用于执行各种存储过程,通过重载返回多种类型,包括INT,DataRow,DataTable,DataSet等,然后大多数的DAL查询都可以写在存储过程里,除非是全表遍历
      

  5.   

    用XML文件做为每个对象的配置文件得自己写一个类似O-R MAP的工具
    否则工作量和每个表写一个类差不多http://www.aspcool.com/lanmu/browse1.asp?ID=1076&bbsuser=csharp
      

  6.   

    我dataAccess层的基类是这样的using System;
    using System.Data;
    using System.Data.SqlClient;
    using System.Text;using eCopy.Common;namespace eCopy.DataAccess
    {
    /// <summary>
    /// eCopyDataAccessBase 的摘要说明。
    /// </summary>
    public class eCopyDataAccessBase : IDisposable
    {
    /// <summary>
    /// 链接串
    /// </summary>
    protected string _connectionString;

    // <summary>
    /// 同步数据的Adapter
    /// </summary>
    protected SqlDataAdapter _dataAdapter; /// <summary>
    /// 数据库链接
    /// </summary>
    protected SqlConnection _connection; /// <summary>
    /// 事务对象
    /// </summary>
    protected SqlTransaction _transaction; /// <summary>
    /// 释放对象的资源
    /// </summary>
    public void Dispose()
    {
    Dispose(true);
    GC.SuppressFinalize(this); // as a service to those who might inherit from us
    }
    /// <summary>
    /// 释放对象中的实例
    /// </summary>
    protected virtual void Dispose(bool disposing)
    {
    if (disposing)
    {
    this._transaction = null;
    if (this._dataAdapter != null)
    {
    if(this._dataAdapter.SelectCommand != null)
    {    
    if(this._dataAdapter.SelectCommand.Connection != null )
    this._dataAdapter.SelectCommand.Connection.Dispose();
    this._dataAdapter.SelectCommand.Dispose();
    }    

    if(this._dataAdapter.InsertCommand != null)
    {    
    if(this._dataAdapter.InsertCommand.Connection != null )
    this._dataAdapter.InsertCommand.Connection.Dispose();
    this._dataAdapter.InsertCommand.Dispose();
    }     if(_dataAdapter.UpdateCommand != null)
    {    
    if (this._dataAdapter.UpdateCommand.Connection != null )
    this._dataAdapter.UpdateCommand.Connection.Dispose();
    this._dataAdapter.UpdateCommand.Dispose();
    }     if(_dataAdapter.DeleteCommand != null)
    {    
    if (this._dataAdapter.DeleteCommand.Connection != null )
    this._dataAdapter.DeleteCommand.Connection.Dispose();
    this._dataAdapter.DeleteCommand.Dispose();
    }     this._dataAdapter.Dispose();
    this._dataAdapter = null;
    } if ( this._connection != null) 
    {
    this._connection.Dispose();
    this._connection = null;
    } }
    }
    ~eCopyDataAccessBase()
    {
    Dispose(false);
    }
    public eCopyDataAccessBase()
    {
    this._connectionString = eCopyConfiguration.ConnectionString;
    this._connection = new SqlConnection(this._connectionString);
    this._dataAdapter = new SqlDataAdapter();
    }
    /// <summary>
    /// CommandBuilder根据指定的查询语句自动生成四个数据库操作的Command,
    /// 然后根据DataSet的DataTable中的记录状态在数据库中执行插入修改或者删除操作
    /// </summary>
    public bool AutoUpdate(
    DataTable dataTable,
    string sqlQuery,
    out string resultInfo)
    {
    resultInfo = "";
    bool result = true;
    try
    {
    if(this._transaction != null)
    {
    this._dataAdapter.SelectCommand = new SqlCommand( sqlQuery,this._transaction.Connection);
    SqlCommandBuilder commandBuilder = new SqlCommandBuilder(this._dataAdapter);

    this._dataAdapter.SelectCommand.Transaction = this._transaction; this._dataAdapter.Update(dataTable);

    }
    else
    {
    this._dataAdapter.SelectCommand = new SqlCommand( sqlQuery,this._connection);
    SqlCommandBuilder commandBuilder = new SqlCommandBuilder(this._dataAdapter); this._connection.Open();
    this._dataAdapter.Update(dataTable);
    this._connection.Close();
    } }
    catch (SqlException sqlException)
    {
    for (int i=0; i < sqlException.Errors.Count; i++) 
    {
    resultInfo += sqlException.Errors[i].Message + "\n" + resultInfo;
    }
    result = false;
    }
    return result; } /// <summary>
    /// 根据指定的查询语句,填充指定的DataSet中的指定的表
    /// </summary>
    public bool AutoFill( 
    DataTable dataTable,
    string sqlQuery,
    out string resultInfo)
    {
    resultInfo = "";
    bool result = true;
    try
    {
    this._dataAdapter.SelectCommand = CreateCommand(sqlQuery);
    this._dataAdapter.Fill(dataTable);
    result = true;
    }
    catch (SqlException sqlException)
    {
    for (int i=0; i < sqlException.Errors.Count; i++) 
    {
    resultInfo = sqlException.Errors[i].Message + "\n" + resultInfo;
    }
    result = false;
    }
    finally
    {
    this._dataAdapter.SelectCommand.Connection = null;
    this._dataAdapter.SelectCommand.Transaction = null;
    }
    return result;
    }
    /// <summary>
    /// 执行此方法后,所有数据库的操作均在参与的事务中进行
    /// </summary>
    /// <param name="transaction">要参与的事务</param>
    public void JoinTransaction(Transaction transaction)
    {
    if(this._transaction != null)
    {
    throw new Exception("对象已经参与另一个事务。");
    }
    else
    {
    this._transaction = transaction.DataBaseTransaction;
    } } /// <summary>
    /// 执行此方法后,所有数据库的操作不再在任何事务中进行
    /// </summary>
    public void QuitTransaction()
    {
    if(this._transaction != null)
    this._transaction = null;
    } }
    }
      

  7.   

    其实不怎么麻烦啊, 你写的那些 DataAcess类 基本操作 大都都有保存,删除,还有简单的查询方法,你做一个抽象类 来完成这些基本功能,还有准备个数据库操作类(这个是有通用的)专门用于直接与数据库操作 。DataAcess通过工厂方法来获得业务实体
      

  8.   

    写一个通用的实体类、控制类
    然后为每一个表写实体类、一个控制类继承通用类,实现通用类中的抽象方法
    实体类、控制类可以自己编写一个代码生成器,读取数据库表,自动生成
    具体的业务通过控制类来实现
    控制类调用实体类的方法实体类提供通用的增、珊、改、查等功能,还提供运行存储过程、sql语句的功能
    如果需要复杂业务,编写sql语句,或者存储过程实现
      

  9.   

    我也碰到这个问题,写了一个程序自动生成类文件:)
    可以看看~
    http://expert.csdn.net/Expert/topic/2196/2196935.xml?temp=.5374414
      

  10.   

    shuncy(天才笨蛋) 把你的东东发一个给我,共同研究吧。
    我们这两贴要求差不多了。
    [email protected]
      

  11.   

    我写了一个从sqlserver到vb的代码生成器,不过用户界面的问题还没有处理好。
    完了我给大家发布。
      

  12.   

    用.net的CodeDom类写一个根据数据库结构生成代码的小程序即可
    这个程序开发时间不长。大概三天左右吧
      

  13.   

    可以参考《.net企业应用高级编程》
    wrox出版社
    它的数据层就是自动生成的
    而且连原代码都给出来了
      

  14.   

    chenhigh(小陈):
    我没有这本书啊,你能否将它的代码给我发过来参考一下,不胜感激,给你高分!
    [email protected]
      

  15.   

    我提一个思路,不知道大家注意否.NET引入的attribute-oriented编程方式。实际上利用元数据将面向对象的business entity或更小的entity info类“置标”上数据访问相关的元信息并在runtime由一个通用的toolkit基类或工具类构建并运行。不好懂哈?我示意性的写两行代码,大家想想是否可行吧。:)以一个Customer数据实体为例,他的entity info class很简单,大致是这个样子:class CustomerInfo
    {
      public Guid CustomerID;
      public string Name;
    }假如你有一个数据库构架(抽象的噢),其中包含Customer table,则通过自定义的custom attribute我们可以将其作为元信息附加到该类上:[SQLTable("Customer")]
    class CustomerInfo
    {
      [SQLColumn]
      public Guid CustomerID;  [SQLColumn]
      public string Name;
    }为了提供一个通用的方法基础,我们令CustomerInfo继承自EntityInfo类:...
    class CustomerInfo: EntityInfo
    {
      ...
    }而在EntityInfo类中提供两个方法,一个用来读,一个用来写,为了抽象不同的数据源,我们把这个任务委托给Data Accessors:class EntityInfo
    {
      public void LoadData(IDataAccessor accessor);
      public void SaveData(IDataAccessor accessor);
    }其中IDataAccessor接口的具体实现者负责具体同底层数据源打交道,把抽象的SQL元数据和实例数据同SQL Server,或Oracle,或OLE DB Data Source连接起来。而LoadData/SaveData则是一个通用的元数据/实例数据处理逻辑。另外还可以提供一个protected ExecuteStoredProc方法来调用存储过程等等。看来还是可行的,至少不用一遍遍的写那些繁琐的生成SqlCommand之类的语句,语句可以从类的元数据中自动生成,甚至可以在数据库自动创建辅助存储过程,等等。
      

  16.   

    以上的方法我有可以运行的原型,不过还没有形成完整的、可以产品化的解决方案。大家可以参考一个叫ORM.NET的产品,思路类似,不过他们是依靠build-time的和VS.NET集成的custom tool来生成类源码的。如果有人对这个通用的runtime data entity wrapper layer framework/toolkit感兴趣的话,可以与我继续探讨。目前我在研究关于master/detail关系、hierarchical关系等的实现。该技术主要是利用.NET Reflection。正如echeng192所说,如果能够做出来应该是一个很有卖点的东东。:)
      

  17.   

    to JGTM2000(铁马小子):
    可以详细点吗?
      

  18.   

    to chenhigh:代码太长,就不贴了。思路虽然不难,不过实现上细节蛮多,好在只要做成框架或工具包,剩下的事情就很简单了。基本上流程是这样的:每个EntityInfo派生类的构造器都调用基类公用的构造器,通过.NET Reflecting获取类的runtime type info并构造出entity schema(表和列的属性),看看类是不是被标记上SQLTable了,取得表名;从中枚取出所有的public fields,对于每一个看看它是不是被标记为SQLColumn了,如果是,将其列入columns arraylist,并将member info同其一起缓冲起来。实际上,有了这些信息,你已经可以动态创建出如下的SQL语句:select @column1 = column1, @column2 = column2 from table这样就可以实现最基本的SELECT功能,具体操作统统委托给IDataSource的实现类去做(这样可以同数据源松耦,甚至开发O/R时你都可以没有数据库,实现一个写内存的data source即可)。对于一个SQL Data Source来讲,它的实现就是利用这个entity info创建的entity schema来动态生成SqlCommand(PS: once per class, 'cause entity schema is static, so no much performance hit during runtime),附上相应的SqlParameters并用业务组件传入的connection/transaction来完成实际的操作。操作结束,entity info将返回的参数赋予entity info实例的fields即可。一个完整的entity info class看起来大概是这样:[SQLTable("Customer")]
    public class CustomerInfo: EntityInfo
    {
      [SQLColumn("CustomerID", PrimaryKey=true, AutoIncrement=true)]
      public int ID;  [SQLColumn]
      public string Name;  [SQLColumn(Type=SqlDbType.VarChar)]
      public string Email;  // constructors
      public CustomerInfo(int ID): base(ID) {}
    }注意,该类只是一个数据传输对象(Data Transfer Object, 参见MSP&P: Enterprise Solution Patterns using MS.NET, P.228),它不封装任何商业逻辑(如验证email是否合法),但可以通过property accessor实现简单的数据逻辑(如Name.Trim().Length>3)。在业务逻辑层,还有一个Customer类contains一个CustomerInfo实例成员,在Customer类(这是一个Business Entity,业务实体类,参见MSP&P: Architect Applications and Services using MS.NET, P.56及MSP&P: Designing Data Tier Components and Passing Data Thru Tiers, P.22)中实现你的商业逻辑(如验证email的合法性,验证身份合法性,加密登录信息等)。简言之,xxxInfo类只含数据,而xxx类则含行为,xxx内contains xxxInfo。从技术特征看,xxxInfo应该是serializable,而xxx类则直接或间接派生自MarshalByRefObject(support remoting)。靠,扯远了,rollback now...在business entity中读写entity info都是和内存中的数据打交道,为了和后台数据打交道,还要有封装数据访问逻辑的实际的data access components(参见MSP&P: 这个自己找吧)。通过entity info的Save/Load方法,传入data source组件,即可完成实际的读写:IDataSource dataSource = new SQLDataSource(connectionString);
    info.Save(dataSource);实际上,数据访问组件中将有更多的代码来处理条件选择(common: byID, byUUID; specific: byEmail, byName)、插入、更新(乐观并发命令生成逻辑、仅更新变化了的数据、等等)、删除以及由存储过程实现的更多行为逻辑。另外从执行环境的角度看,data source的根环境实际是一个transaction(手动创建的或默认自动创建的),因此entity info can be easily transactional! 只要在几个business entity间共享transaction对象即可。哇赛,细节太多了其实关键是思路,思路有了一切基本上就顺水推舟的出来了——只要你把.NET玩儿的转。:)
      

  19.   

    to 铁马小子:
      EntityInfo类继承了那个类和哪些接口?
      

  20.   

    codeproject有一篇文章是能根据SQLSERVER的表自动生成类模板的, 非常好用, 共享给大家
    http://www.codeproject.com/useritems/dbhelper.aspSQL Stored Procedure Wrapper & Typed DataSet Generator for .NET
    By leppie This a small tool that will generate static methods in a class that acts as wrapper for SQL stored procedures. It either outputs a source file or a compiled assembly. Also supports automatic dataset generation
      

  21.   

    你们说得很有深度。
    我原先也想用duwamish中的模式写一个程序,但是发现代码量太大。我没有坚持,现在变成了,用asp.net和C#写一个界面+访问代码的程序和以前的VB模型差不多。
    惭愧!
    或者我没有真正领会OO的好处。反而有时觉得繁琐。
    见笑。
      

  22.   

    最近也刚做完一个站点,采用的是多层结构(细分):
                            
    表结构->存储过程->数据服务层基类(每个模块数据服务层都继承自此类)->
      业务层基类(每个模块的业务层继承此类)->表示层基类(每个模块表示层继承此类)只要把数据库和所有基类构造好,整个站点也就差不多了,只需添砖加瓦了
      

  23.   

    推荐nTierGen工具自动数据库结构生成中间层的代码(包括存储过程,数据访问对象,商务对象)
    注:下载的演示版,每次只能生成两个表。
    站点:http://www.gavinjoyce.com如果需要无限制版本,给我留言。(准备好你的Money,共享版本非免费)
      

  24.   

    关于使用Attribute来实现dal的思路,csdn上有一篇文章已经介绍过这种方法:Attribute在.NET编程中的应用(四)(http://www.csdn.net/Develop/Read_Article.asp?Id=19591),但个人觉得,使用代码生成器似乎更方便,dal层中各个表的Insert、Update、Delete、Select都非常相似,.Net企业应用高级编程提供了一个这样的生成器来完成任务,可以到wrox的网站上去查找5911以下载代码,但如果真的要实际应用的话,可能还需要改造。
    这里http://www.deklarit.com/也有一个生成器,但是要钱的,我没有实际使用,看了演示,觉得比nTierGen好——nTierGen我用过1.2.4。
    MSDN Magazine 2003年第4期上有一篇Advanced T-SQL: Automate the Generation of Stored Procedures for Your Database,讲到如何自动生成sql server的sp,并且提供源代码下载(也是sp)。
    以上是我搜集到的一些与dal有关的内容,发布出来和大家共享,共同学习,共同提高。
      

  25.   

    呵呵,班门弄斧了, Attribute在.NET编程中的应用本来就是niwalker(原作) 。
      

  26.   

    O-R的映射是很麻烦而且负责的,除非你用商品化的工具.看贴看到一个问题:luckycrazy():
    写一个基类,包含增删改查,还包括存储过程的调用,其他类从这个类继承luckycrazy()说的是个错误,这是错误应用继承,应该用委托.
      

  27.   

    O-R的映射是很麻烦而且负责的,除非你用商品化的工具.看贴看到一个问题:luckycrazy():
    写一个基类,包含增删改查,还包括存储过程的调用,其他类从这个类继承luckycrazy()说的是个错误,这是错误应用继承,应该用委托.
      

  28.   

    自己做个代码生成器,这是csdn里 bugMicrosoft OLE DB Provider for SQL Server 错误 '80040e31' 超时已过期 /Expert/reply.asp,行105