c# - 哪种连接数据库的方式更有效?

标签 c# asp.net sql-server coding-style data-access-layer

与同事意见不一致,在这一点上,我不在乎谁是对的,我更好奇哪个是更好的解决方案,以便我可以继续使用它。

我们有不同的方式来访问系统。

选项#1: 使用以下代码创建数据库。

using Microsoft.Practices.EnterpriseLibrary.Data;

namespace Ivans.Healthcare.CommercialAccess.Data
{
    public abstract class DataAccess : DataHelperBase
    {
        public const int commandTimeout = 7200;
        private static Database m_db = null;
        public StringBuilder Status {get; set;}

        public DataAccess()
        {
            this.Status = new StringBuilder();

            if (m_db == null)
            {
                bool bIfRunsOnWebService = false;
                try
                {
                    if (DynamicConfigurationManager.AppSettings["WebService"] != null)
                    {
                        bIfRunsOnWebService = true;
                    }
                }
                catch {}

                if (!bIfRunsOnWebService)
                {
                    m_db = DatabaseFactory.CreateDatabase(DataAccessResource.IDS_DB_ALIAS);
                }
                else
                {
                    m_db = CreateDatabase(DataAccessResource.IDS_WS_DB_ALIAS);
                }
            }
        }

然后每次需要调用存储过程时,该方法将包含如下内容:

public IEnumerable<InquiryServiceType> GetActive(bool is5010)
{

    Database db = getDB();
    DbCommand dbCmd = db.GetStoredProcCommand(DataAccessResource.IDS_SP_SEL_InquiryServiceTypeData_ListServiceTypes);
    db.AddInParameter(dbCmd, DataAccessResource.IDS_SP_SEL_InquiryServiceTypeData_ListServiceTypes_Is5010Request, DbType.Boolean, is5010);

    DataSet ds = new DataSet();
    db.LoadDataSet(dbCmd, ds, new string[] { DataAccessResource.IDS_TBL_InquiryServiceTypeData });

    return DataSetTranslator.TranslateInquiryServiceTypeDataSet(ds);
}

选项 2

此选项更加模块化,并试图创建一个通用的数据库方法。

    private Database currentDB;
private const int commandTimeout = 7200;

public DataAccess(Common.Enums.ConnectionString currentConnection)
{
    currentDB = DatabaseFactory.CreateDatabase(currentConnection.ToDescription());
}

public IEnumerable<T> SelectMany<T>(string spName, params Param[] parameters) where T : IDataPopulate<T>, new()
{
    var storedProcedure = CreateStoredProcedureCommand(spName);
    AddParameters(storedProcedure, parameters);

    IDataReader myReader = null;
    IList<T> listOfItems = new List<T>();

    try
    {
        myReader = currentDB.ExecuteReader(storedProcedure);
        if (myReader == null)
        {
            return listOfItems;
        }

        while (myReader.Read())
        {
            listOfItems.Add(new T().FillObject(myReader));
        }

        return listOfItems;
    }
    catch (Exception ex)
    {
        string message = string.Format("Error Message: {0}\r\nStored Procedure: {1}\r\n", ex.ToString(), spName);
        throw new Exception(message);
    }
    finally
    {
        DataAccessDisposal.DataReader(myReader);
        DataAccessDisposal.StoredProcedure(storedProcedure);
    }
}

然后调用数据库将如下所示:

public IEnumerable<InquiryServiceTypes> GetAll(int payerID)
{
    Param payerIdParam = new Param("@payerID", DbType.Int32, payerID);
    return dataAccess.SelectMany<InquiryServiceTypes>("dbo.proc_PayersInquiryServiceTypesSel", payerIdParam);
}

结论

每个部分中肯定有编码不正确的地方。我很确定有一个中间地带可以达到,那就是最有效的代码。

上面的代码有两点效率低下。首先是它最初是如何连接到数据库的。二是数据一旦返回,你怎么处理。我很想讨论这两个问题,但我觉得第一个在这一点上更为重要。

谢谢, C

最佳答案

我想简单地说:已经有抽象可以做到这一点(而且做得很好)。如果您可以处理创建连接,例如,使用 dapper-dot-net :

return connection.Query<InquiryServiceTypes>(
        "dbo.proc_PayersInquiryServiceTypesSel",
        new { payerId }, commandType: CommandType.StoredProcedure);

这将在大量缓存的 IL 中为您编写所有参数化和具体化。无需编写复杂的 Fill 方法或 populate 方法,而且非常非常快(与手动编写所有 ADO.NET 阅读器代码的性能相同,但没有枯燥的代码和拼写错误的机会)。

手动编写所有这些 Fill 方法效率(对于开发人员而言)。

注意上面;匿名类型正在定义参数,即它说“有一个名为 payerId 的 int 参数,其值与传入的值相同”。您还可以:

new { id = payerId, name = "abc", allData = true }

这会将 @id (int) 与 payerId 的值相加,@name (nvarchar) 与值 'abc ',以及值为 1@allData(位)。


修改评论中的要点:

  • 连接池是正交的,因为它在默认情况下自动完成(使用 SQL 服务器),只要您及时释放连接
  • entlib 在没有任何正当理由的情况下添加了 IMO 开销。与 entlib 通信的代码实际上与与原始 ado.net 通信的代码相同,只是更加臃肿和间接。我会避免使用 entlib,除非你真的使用它来让你的生活更轻松
  • 加载数据集总是开销很大; DataTable 等很复杂——比加载 POCO 模型复杂得多。 只是加载一个数据集,这样你就可以使用数据集加载一个对象模型是低效的,并且会在需要收集的堆上产生不必要的垃圾,而且有很多步骤(适配器等) , 所有这些都需要时间
  • DataTable 方法还要求完全读取表,而不是非缓冲假脱机(可能使用原始读取器和迭代器 block );如果您的结果非常大,这可能很重要
  • 在介绍的两种方法中,第二种方法在我看来更可取,但我喜欢它的界面;这是糟糕的“关注点分离”——POCO 的工作是表示域对象,而不是了解数据库
  • 如上所述,有与第二个选项类似的选项,更少实现/维护工作,并且不会引入 SoC 问题;我会非常感兴趣地看这个
  • 此类选项还可以为您解决更复杂的场景;多个网格;水平连接(进入子对象);等等

关于c# - 哪种连接数据库的方式更有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8327602/

相关文章:

sql-server - 重命名 Identity 表并导致 EF6 迁移失败

C# - 四舍五入整数除法

mysql - 获取插入查询以在 . asp.net中VB点击事件

asp.net - 如何在 Asp.net MVC 中使用代码优先方法更新模型和数据库

javascript - 我可以调用 XmlHttpRequest 中的任何方法吗?不仅是 GET、POST、PUT

c# - 使用相同的参数化查询添加多个 SQL 值?

java - SQL Server : Data more fractional digits in Java

c# - 将 C# 代码中的值检索到 NLog.config 文件中

c# - 展平 IEnumerable<string> - SelectMany 问题

c# - 写一个C#脚本测试上百个域名