如何在 ASP.NET 中组织数据访问层 (DAL)

Posted

技术标签:

【中文标题】如何在 ASP.NET 中组织数据访问层 (DAL)【英文标题】:How to organize Data Access Layer (DAL) in ASP.NET 【发布时间】:2012-01-05 13:38:32 【问题描述】:

我有一个用 C# 开发的 ASP.NET Web 窗体应用程序。

我想通过将 DAL 任务与背后的代码分开来构建我的应用程序。

我在 App_Code 中创建了一个类 DBUtilities,它负责与数据库的通信,以避免整个应用程序中出现重复的代码。该类具有获取数据表、标量值等的方法……它们接受 连接字符串名称查询命令 作为参数作为字符串。

问题是我的代码中仍然有所有查询的命令。其中许多在页面周围重复,这会导致维护问题。

我想知道创建一个包含许多 字符串属性 的(静态)类 QueryRepository 并为每个属性关联一个特定的查询命令是否是一个好习惯。每次我想执行查询命令 MyCommand 时,我都会将字符串的 QueryRepository.MyCommand 属性传递给 DBUtilities 类。此外,如果我需要更改查询命令,我只在 QueryRepository 类上进行。

这是组织我的 DAL 的好方法吗?

【问题讨论】:

【参考方案1】:

对于 ASP.NET Web 表单,实现 Model-View-Presenter (MVP) 模式可能是将您的逻辑和数据库查询与背后的 UI 代码分离的一种好方法。您必须编写一个 Presenter 类,该类具有对视图接口的通用引用,并且其中有一个模型,其中包含数据库查询、逻辑等。演示器将在其所有函数中调用通用视图接口的函数。然后您可以编写实际的 ASP.net 视图。在视图中,您实例化并引用此演示者,并在实例化演示者时将 self 对象,即 ASP 视图本身(使用“this”关键字)注入演示者。您可以根据需要为您的演示者类设计适当的继承,以便它们可重用并且可以进行单元测试。

针对 CiccioMiami 的询问添加:

这里有几个链接开始

http://www.codeproject.com/KB/aspnet/AspNet_MVP.aspx

http://wiki.asp.net/page.aspx/340/mvp-pattern/

这里解释了 MVC 和 MVP 模式的区别:http://www.codeproject.com/KB/architecture/DotNetMVPFramework_Part1.aspx

此外,对于 ASP.net Web 表单架构,请求与页面生命周期紧密耦合。您有一系列页面生命周期事件,开发人员在每个事件中编写代码。因此,业务逻辑与 UI 视图紧密耦合。在一段时间内,这对于代码可维护性和单元测试来说不是一个好情况。 ASP.net Web 表单中的单元测试很困难,因为它很难模拟请求和页面生命周期事件。在 MVC 中,请求首先到达控制器。控制器将模型用于业务逻辑并将模型传递给视图。视图使用模型数据呈现,并作为响应返回给用户。控制器对工作流程有更大的控制。您可以像在独立应用程序中一样测试模型、DTO 传输等。对于 Web 表单,没有控制器,请求直接到达作为视图的 ASP.net 页面。用户无能为力。很好,微软意识到了这个问题,我们有 ASP.net MVC。 ASP.net webforms 的 MVP 模式将在一定程度上解决代码分离问题。最好的选择是使用 ASP.net MVC,如果没有,那么您可以将 MVP 与 Webforms 一起使用。

【讨论】:

哇,这看起来是个不错的解决方案。你知道任何关于在 ASP.NET 中实现 MVP 的教程吗?它与 MVC 有何不同(模式不是框架)【参考方案2】:

长期回答:我真的可以推荐你阅读Professional Enterprise .NET

ASP.NET 网站上有一个很好的 repository pattern 示例,值得一看。

我不是专家,但如果您的 DAL 能够符合最佳实践模式,那么它更有可能成为组织它的好方法。

我很难在没有具体示例的情况下遵循您的 DAL 设计,因此不确定我是否可以提供帮助。

【讨论】:

谢谢,但您的链接是指 MVC 框架。我使用 ASP.NET Web 窗体 我认为该链接很好地描述了未链接到 mvc 的存储库模式。 +1【参考方案3】:

几个步骤:

将 DAL、BLL 代码与表示 (UI) 层分离是一种很好的做法,但相应地执行以下步骤会有所帮助。

    创建 DTO(数据传输对象)或实体 从表示层填充 DTO/实体 将其传递给 BLL 层的公共方法并验证业务逻辑 然后将 DTO/Entity 传递给 DAL 层(在 DAL 层,创建一个返回 Command 的方法,然后将您的 CommandText、CommandType 和设置值、数据类型和大小设置为所有参数,同时创建执行方法得到命令并返回结果)。 最后,执行你想要的执行方法(在 DAL 层创建)

【讨论】:

【参考方案4】:
namespace DAL

    public class DBAccess
    
        private IDbCommand cmd = new SqlCommand();
        private string strConnectionString = "";
        private bool handleErrors = false;
        private string strLastError = "";
        public DBAccess()
        
            ConnectionStringSettings objConnectionStringSettings = ConfigurationManager.ConnectionStrings["connectionString"];
            strConnectionString = objConnectionStringSettings.ConnectionString;
            SqlConnection cnn = new SqlConnection();
            cnn.ConnectionString = strConnectionString;
            cmd.Connection = cnn;
            cmd.CommandType = CommandType.StoredProcedure;
        

        public SqlConnection OpenSqlConnection()
        
            try 
                SqlConnection Conn = new SqlConnection(strConnectionString);
                Conn.Open();
                return Conn;
             catch (SqlException e) 
                throw e;
             catch (Exception ex) 
                throw ex;
            
        

        public IDataReader ExecuteReader()
        
            IDataReader reader = null;
            try 
                this.Open();
                reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
             catch (Exception ex) 
                if (handleErrors) 
                    strLastError = ex.Message;
                 else 
                    throw;
                
            
            return reader;
        

        public IDataReader ExecuteReader(string commandtext)
        
            IDataReader reader = null;
            try 
                cmd.CommandText = commandtext;
                reader = this.ExecuteReader();
             catch (Exception ex) 
                if ((handleErrors)) 
                    strLastError = ex.Message;
                 else 
                    throw;
                
            
            return reader;
        
        public object ExecuteScalar()
        
            object obj = null;
            try 
                this.Open();
                obj = cmd.ExecuteScalar();
                this.Close();
             catch (Exception ex) 
                if (handleErrors) 
                    strLastError = ex.Message;
                 else 
                    throw;
                
            
            return obj;
        
        public object ExecuteScalar(string commandtext)
        
            object obj = null;
            try 
                cmd.CommandText = commandtext;
                obj = this.ExecuteScalar();
             catch (Exception ex) 
                if ((handleErrors)) 
                    strLastError = ex.Message;
                 else 
                    throw;
                
            
            return obj;
        
        public int ExecuteNonQuery(SqlConnection DBConnection, SqlTransaction DBTransaction, bool IsTransRequired)
        
            int i = -1;

            try 
                if ((DBTransaction != null)) 
                    cmd.Transaction = DBTransaction;
                
                i = cmd.ExecuteNonQuery();

             catch (Exception ex) 
                if (handleErrors) 
                    strLastError = ex.Message;
                 else 
                    throw;
                
            
            return i;
        
        public int ExecuteNonQuery(string commandtext, bool IsTransRequired)
        
            SqlConnection DBConnection = null;
            SqlTransaction DBTransaction = null;
            int i = -1;
            try 
                cmd.CommandText = commandtext;
                if (((DBConnection == null))) 
                    this.Open();
                    DBConnection = (SqlConnection)this.cmd.Connection;
                    if (IsTransRequired == true) 
                        if (((DBTransaction == null))) 
                            DBTransaction = DBConnection.BeginTransaction();
                        
                    
                    i = this.ExecuteNonQuery(DBConnection, DBTransaction, IsTransRequired);
                    if ((DBTransaction != null)) 
                        DBTransaction.Commit();
                    
                

             catch (Exception ex) 
                if ((DBTransaction != null)) 
                    DBTransaction.Rollback();
                
                if (handleErrors) 
                    strLastError = ex.Message;
                 else 
                    throw;
                
             finally 
                this.Close();
            
            return i;
        
        public DataSet ExecuteDataSet()
        
            SqlDataAdapter da = null;
            DataSet ds = null;
            try 
                da = new SqlDataAdapter();
                da.SelectCommand = (SqlCommand)cmd;
                ds = new DataSet();
                da.Fill(ds);
             catch (Exception ex) 
                if ((handleErrors)) 
                    strLastError = ex.Message;
                 else 
                    throw;
                
            
            return ds;
        
        public DataSet ExecuteDataSet(string commandtext)
        
            DataSet ds = null;
            try 
                cmd.CommandText = commandtext;
                ds = this.ExecuteDataSet();
             catch (Exception ex) 
                if (handleErrors) 
                    strLastError = ex.Message;
                 else 
                    throw;
                
            
            return ds;
        
        public string CommandText
            get 
                return cmd.CommandText;
            
            set 
                cmd.CommandText = value;
                cmd.Parameters.Clear();
            
        

        public IDataParameterCollection Parameters
            get return cmd.Parameters;
        
        public void AddParameter(string paramname, object paramvalue)
        
            SqlParameter param = new SqlParameter(paramname, paramvalue);
            cmd.Parameters.Add(param);
        

        public void AddParameter(IDataParameter param)
        
            cmd.Parameters.Add(param);
        
        public string ConnectionString 
            get  return strConnectionString; 
            set  strConnectionString = value; 
        
        private void Open()
        
            cmd.Connection.Open();
        

        private void Close()
        
            cmd.Connection.Close();
        
        public bool HandleExceptions
            get return handleErrors;
            set handleErrors = value;
        
        public string LastError
            get return strLastError;
        
        public void Dispose()
        
            cmd.Dispose();
        
    

【讨论】:

以上是关于如何在 ASP.NET 中组织数据访问层 (DAL)的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET 应用程序中自动生成 DAL

ASP.NET MVC:BLL 和 DAL 到存储库设计

在ASP.NET中,三层架构,Web ,BLL,DAL,Models这四个的引用关系是?

ASP.NET三层架构DAL层连接数据库的方法

如何将数据从表示层传递到业​​务逻辑层? (ASP.NET MVC 5)

ASP.NET MVC 的三层架构 + EF数据模型