【问题标题】:How to populate a generic list of objects in C# from SQL database如何从 SQL 数据库填充 C# 中的通用对象列表
【发布时间】:2010-03-16 18:29:03
【问题描述】:

我只是在学习 ASP.NET c# 并尝试将最佳实践融入我的应用程序。我读到的所有内容都说基于关注点分离将我的应用程序分层为 DAL、BLL、UI 等。我没有传递数据表,而是考虑使用自定义对象,以便我松散地耦合到我的数据层,并可以利用 VS 中的智能感知。我假设这些对象会被视为 DTO?

首先,这些对象位于我的图层中的什么位置? BLL、DAL 还是其他?

其次,从 SQL 填充时,我应该循环通过数据读取器填充列表还是先填充数据表,然后循环遍历表以填充列表?我知道您应该尽快关闭数据库连接,但是填充数据表然后循环遍历列表似乎会产生更多开销。

第三,我最近看到的一切都说使用 Linq2SQL。我打算学习 Linq2SQL,但此时我正在使用一个没有外键设置的旧数据库,并且我没有能力在 atm 修复它。另外,在我开始接触像 nHibernate 这样的 ORM 解决方案之前,我想了解更多关于 c# 的信息。同时,我不想为每个查询输入所有连接和 SQL 管道。现在可以使用 Enterprise DAAB 吗?

【问题讨论】:

    标签: c# asp.net sql-server


    【解决方案1】:

    一个问题你有很多问题。

    Linq2SQL 只是一种 ORM,如果你走这条路,我会看看实体框架(微软的 orm)。

    让我们稍微谈谈分层应用程序,以帮助您了解如何填充对象。 您的典型数据库应用程序由 3 层组成(有人说 4 并将数据库本身称为一层,这真的没关系)。您有以下内容:

    • 用户界面
    • BLL
    • DAL

    因此,您的通信是 UI 与 BLL 对话,BLL 与 DAL 对话。 DAL 将一些数据返回给 BLL,然后 BLL 将其返回给 UI。我不知道谁告诉你数据集/表格不好……当然阅读器速度更快,但这并不意味着使用数据表不好。

    让我举个例子。别再把你的 DAL 看成一个简单的类了。开始将 DAL 层视为不同类的整个文件夹。其中一个类是静态 DB 类。它是静态的,因为您正在处理一个数据库(在大多数情况下),因此无需实例化该类。所以它可能看起来像这样:

    public static class DB {
    private static readonly string connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
    private static readonly DbProviderFactory factory = DbProviderFactories.GetFactory(dataProvider);
    
    public static int Update(string sql)
            {
                using (DbConnection connection = factory.CreateConnection())
                {
                    connection.ConnectionString = connectionString;
    
                    using (DbCommand command = factory.CreateCommand())
                    {
                        command.Connection = connection;
                        command.CommandText = sql;
    
                        connection.Open();
                        return command.ExecuteNonQuery();
                    }
                }
            }
    
    public static DataTable GetDataTable(string sql)
            {
                using (DbConnection connection = factory.CreateConnection())
                {
                    connection.ConnectionString = connectionString;
    
                    using (DbCommand command = factory.CreateCommand())
                    {
                        command.Connection = connection;
                        command.CommandType = CommandType.Text;
                        command.CommandText = sql;
    
                        using (DbDataAdapter adapter = factory.CreateDataAdapter())
                        {
                            adapter.SelectCommand = command;
    
                            DataTable dt = new DataTable();
                            adapter.Fill(dt);
    
                            return dt;
                        }
                    }
                }
    }
    

    其中一些来自dofactory网站。学习如何使用设计模式的绝佳资源。无论如何,这只是一个 .class 文件。现在您需要另一个来表示 CustomerDAO(客户数据访问对象)。

    好的,那么您如何使用您创建的那个 DB 类(我会使用存储过程的组合,但为了使这篇文章变得简单,让我们暂时避免存储过程)。如果我需要获取客户,我可以这样定义:

    public IList<Customer> GetCustomers()
    {
        StringBuilder sql = new StringBuilder();
        sql.Append(" SELECT CustomerId, CompanyName, City, Country ");
        sql.Append("   FROM Customer ");
    
        DataTable dt = Db.GetDataTable(sql.ToString());
    
        return MakeCustomers(dt);
    }
    

    请记住,这是在一个完全不同的 .class 文件中。好的,那么如何让客户看起来:

    private IList<Customer> MakeCustomers(DataTable dt)
            {
                IList<Customer> list = new List<Customer>();
                foreach (DataRow row in dt.Rows)
                    list.Add(MakeCustomer(row));
    
                return list;
            }
    

    所以我在这里做的是我有一个充满客户的数据表。我需要遍历数据表的每一行并让客户:

    private Customer MakeCustomer(DataRow row)
            {
                int customerId = int.Parse(row["CustomerId"].ToString());
                string company = row["CompanyName"].ToString();
                string city = row["City"].ToString();
                string country = row["Country"].ToString();
    
                return new Customer(customerId, company, city, country);
            }
    

    所以这个客户是新客户并存储在客户列表中。

    这只是数据访问层功能的一个小示例。数据库类只存储连接字符串和函数以获取数据集或获取数据表,甚至在您的情况下获取数据读取器(您也可以这样做)。 CustomerDAO 类只是一个处理客户对象的类,并且可以实现 ICustomer 接口。

    那么 Customer 类本身在哪里呢?它可以作为业务层在另一个文件夹中,因为它只是一个业务对象。在这里,您可以在客户类中设置验证和必填字段。

    您的 UI 根本没有与数据读取器、数据集或 SQL 相关的任何内容。您的业​​务层也与它无关(它定义了您的业务对象背后的一些规则)。您的 dal 可以非常灵活(可以与 SQL、Oracle 等一起使用),或者如果您打算这样做,则可以限制为 SQL Server。不要过度杀伤您的应用程序。如果您是一名 MS 专家并且确定只使用 SQL Server,请不要尝试推出适用于任何供应商的终极 DAL,从而使您的工作变得困难。可以使用 SQLCommand、SQLConnection 等。

    【讨论】:

    • 你为什么不把get customers、make customers、make customer结合成一个单一的方法呢?
    • @developr - 那么你将拥有一个丑陋的大功能。您需要分离关注点,以免使功能复杂化。一个函数应该简单地完成一个工作/任务。如果我把这一切合二为一,您将获得客户,加上通过客户获取/循环,加上通过分配空间来新客户,加上为客户对象分配值,最后将客户添加到列表中。您可以一次性完成所有操作,但这会使您的功能复杂化。在我的示例中,可读性也更加简单。
    • 如何以正确的方式将参数添加到 DB 类中的 Update 方法中?我不认为,你会喜欢: DB.Update("update table set username='" + varusername + "' WHERE x=" + varx + "); ...所以你会传递带有参数的 SqlCommand或字典或键/值列表并在 Update 方法中构建 sqlcommand。我认为该方法的可用性应该尽可能广泛/通用。
    • @Jesper - 这只是一个例子 - 你看到什么是必要的,你是否传递一个 SqlCommand 对象并调用一个存储过程完全取决于你和你的实践。
    【解决方案2】:

    去看看 Telerik 的 OpenAccess ORM。您不必将它用作“ORM”,但它可以让您快速为表生成类,而无需全部输入。然后,您可以在 DAL 中将这些强类型类用于您想要的任何内容,无论是自定义编写的还是基于 ORM 的其他内容。在这种情况下,您只是将它用于代码生成,以帮助您快速入门(这些对象非常基本和简单 - 即如果您要手写它们,您会从哪里开始)。

    至于从其他对象中抽象出 DAL 对象,请查看 WCF。您可以将它放在每一层之间(UI/Biz/DAL),它会生成代理对象来处理您的关注点分离。

    【讨论】:

      猜你喜欢
      • 2020-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多