ASP.net最佳实践 - 我从哪里连接到数据库?

时间:2011-01-25 14:15:20

标签: c# asp.net database-connection

cn = new SqlConnection(
         ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString());
cn.Open();

假设我有内容页面和母版页,这段代码应该放在哪里?

我应该将它放在母版页Page_Init中吗?那么在我的内容页面上的每个执行阶段都可以完全访问它吗?

我习惯于经典ASP,所以我通常会这样做:

Declare variables

Open connection

process code

Close connection

Render HTML

但是.net中的页面生命周期有很多阶段,所以我想知道放置这段代码的最佳位置是什么?

此连接是否需要关闭,还是垃圾处理会为我处理?

6 个答案:

答案 0 :(得分:6)

对于我来说,id创建一个DataAccess层,以便我可以删除代码隐藏文件中的数据库连接。然后我的webapp将引用Dal并公开一个允许来自前端的Dal交互的公共方法

在打开和关闭Dal连接方面 - 将其包装在using语句中 - 在需要时负责打开和关闭连接。

有关此内容的更多信息,请访问此处 - http://davidhayden.com/blog/dave/archive/2005/01/13/773.aspx

答案 1 :(得分:3)

我也会选择数据访问层,但为了更直接地回答你的问题,这里是我如何在ASP.NET中执行此操作,同时处理事务。

  1. 覆盖OnPreInit:初始化连接,打开它并开始新事务
  2. 覆盖OnUnload:提交/回滚事务,关闭连接
  3. 覆盖Dispose:处理连接和事务
  4. 如果出现问题,我还会添加一个用于请求事务回滚的VoteRollback()方法。页面执行继续(您必须通过代码处理问题)但是当页面被卸载时,事务将被回滚

答案 2 :(得分:2)

在.Net中,它取决于您使用的结构。如果通过手动使用SqlConnection对象显式连接,则需要直接管理其连接。如果您使用数据集tableadapter对象或带有LINQ的DataContext对象(我的个人建议),通常会为您管理连接,但您需要将对象封装在使用块中以确保正确收集它。

我们团队对“最佳实践”的考虑是构建一个通用数据管理器,在我们的公共数据类中实现IDisposable,该数据类处理任何基于连接的对象的延迟加载以检索数据。这样,我们可以强制关闭该数据管理器的dispose事件中的任何连接,以保持其清洁。

修改

我总是从格思里开始 http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx

101 LINQ Samples

http://krisvandermotten.wordpress.com/2006/11/30/creating-a-data-access-layer-with-linq-to-sql-part-2/

下面是我的标准BaseDataManager的代码示例。我很可能很久以前就已经为它创建了一个界面,但是抽象的一点似乎让我的其他团队成员能够很好地采用它。我发布这个代码没有保修,但它适用于我,它使我的连接池保持良好和干净(我们对存储在数据库中的文档信息进行了大量的数据提取)。我删除了许多其他基本方法以保持简单,以下是直接回答您问题的部分:

[Serializable()]
public abstract class BaseDataManager : IDisposable
{

    private bool _disposedValue = false;
    private SqlConnection _connectionObject = null;

    public BaseDataManager()
    {

    }

    public BaseDataManager(string connectionString)
    {
        this.SqlConnectionString = connectionString;
    }

    public BaseDataManager(string connectionString, string username, string password)
    {
        if (!connectionString.EndsWith(";")) connectionString += ";";
        this.SqlConnectionString += "User ID=" + username + ";password=" + password;
    }

    public string SqlConnectionString
    {
        get;
        set;
    }

    public virtual SqlConnection Connection
    {
        get
        {
            if (_connectionObject == null && !String.IsNullOrEmpty(this.SqlConnectionString))
                _connectionObject = new SqlConnection(this.SqlConnectionString);
            return _connectionObject;
        }
        set
        {
            _connectionObject = value;
        }
    }

    #region IDisposable Support
    /// <summary>
    /// (Protected) Method that performs actual cleanup on dispose. This interface
    /// has been implemented to clean up data connections that are left stranded
    /// when the class is disposed while the connection possibly remains open in
    /// the connection pool. This opportunity is also used to free up the private
    /// variables of the class.
    /// </summary>
    /// <param name="disposing">Used for explicitly calling Dispose</param>
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposedValue)
        {
            if (disposing)
            {
                //---------------------------------------------------------------------------------------------
                // Close the connection object prior to setting it to nothing
                //---------------------------------------------------------------------------------------------
                if (_connectionObject != null) _connectionObject.Close();
                _connectionObject = null;
            }

            _disposedValue = true;
        }
    }

    /// <summary>
    /// (Public) Method that implements IDisposable. This code is autogenerated 
    /// the implementation interface in the VS IDE. Do not change this code.
    /// </summary>
    public void Dispose()
    {
        // Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    #endregion

}

答案 3 :(得分:2)

我建议您创建一个单独的类库项目,该项目公开与数据库中的表相关的类。然后提出对该项目的引用,然后离开。要简化打开/关闭连接,编写类等,请查看Subsonic,它将为您映射所有表,然后您可以在代码隐藏中执行类似的操作。

Product prod = Product.Find(3);
prod.Name = "iPhone";
prod.Save();

答案 4 :(得分:1)

只有在需要数据库中的数据时才应该使用它。

如果您没有创建DAL图层,那么您可以将此事件视为page_load或onClick事件。您不应仅仅为了在页面上打开连接而打开连接。

用于打开连接的代码片段

SqlConnection conn = null
try
{
    conn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString);
    conn.Open()

    // do something with the connection
}
catch(Exception ex)
{
    //log error
}
finally
{
    // clean up connection
    if(conn!=null)
    {
        //check if connetion is open, if it is close it / dispose        
    }

}

答案 5 :(得分:1)

规则的第一个拇指,将Domain层与ASP.NET细节/ View分离。

很多人为Domain层创建一个类库,这样就可以保证Page / View相关的代码不会与它混合。

因此,您将拥有一个域层,您可以在其中使用User,Comment等等类......这些类将与数据库通信。我通常有一个DbUser类,其中发生所有数据库交互,DbUser继承DbQuery,它为您创建连接。这样我就可以将数据库交互代码完全保存到Db {ClassName}类和DbQuery中。如果你想保持代码真正有条理,它真的会有所帮助。

简单场景: 当我收到查看特定用户的个人资料的页面请求时,我只需执行User.GetUser(id);,其中id是用户的用户ID。 User类有一个静态方法GetUser,它创建一个新的DbUser实例并在那里调用getUser方法。 DbUser中的getUser方法创建一个连接和一个查询到数据库,然后它返回一个User的实例,瞧,你就可以得到它。

我希望我的答案可以帮助你朝着正确的方向前进,虽然这可能有点偏离主题。

更新:通过将域层与网站分离,您可以有更多选项,例如将类库重新用于与同一数据库交互的另一个项目。