使用多个SQL连接

本文关键字:SQL 连接 | 更新日期: 2023-09-27 18:28:17

我目前正在通过练习面向对象编程来发展我的编码技能。

我正在使用大量的SQL连接来检索初始化类对象的信息。不过,我相信我做得不好,因为我同时初始化了大量的SQL连接。我经常需要同时运行几个连接,以便完成对主类的初始化。下面是我的意思的一个简短例子。

我有好几节课。每个类都有不同类类型的几个属性。下面是一个简单的例子,说明它的主要外观:

public class UserAccount
{
    public long UserId { get; set; }
    public string UserName { get; set; }
    public Address UserAddress { get; set;}
}
public class UserAddress
{
    public long AddressId { get; set; }
    public string Address { get; set; }
}

现在,为了检索关于这些类中每一个的信息,我正在使用特定的方法从数据库中提取每个类属性的值。以下是我的方法如何查找类UserAccount:

public static UserAccount GetUserAccountById(long id)
{
    UserAccount result = null;
    using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString))
    {
        using (SqlCommand cmd = new SqlCommand(string.Empty, con))
        {
            cmd.CommandText = "SELECT * FROM UserAccounts WHERE UserId = @Id";
            cmd.Parameters.AddWithValue("@Id", id);
            con.Open();
            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                if (reader.Read())
                    result = RetrieveFromDatabaseRow(reader);
            }
            con.Close();
        }
    }
    return result;
}
public static UserAccount RetrieveFromDatabaseRow(SqlDataReader reader)
{
    try
    {
        return new UserAccount
        {
            UserId = (long)reader["UserId"],
            UserName = (string)reader["UserName"],
            UserAddress = UserAddress.GetUserAddressById((long)reader["PrimaryAddressId"])
        };
    }
    catch (Exception unhandledException)
    {
        GlobalMethods.LogException(unhandledException);
        return null;
    }
}

现在UserAddress.GetUserAddressById方法与我的第一个类的提取方法基本相同。它初始化连接并运行SQL命令。

为什么我认为我做错了:目前的执行方式会导致几个SQL连接同时打开(在我的示例中只有2个,但在我的实际项目中还有更多)。

我想做一个巨大的SQL语句,将所有需要的SQL表连接到一个命令中,然后提取所有这些信息,以便初始化主类,而无需从其属性(例如UserAddress类)请求其他信息。但这对我来说并不好笑,因为我经常需要同时检索很多信息,有时一句话是不够的。此外,编写一个连接十个表的庞大SQL语句是一件令人头疼的事。

我正在考虑创建一个全局SqlConnection变量,该变量将只初始化一次,并且我的所有SQL查询都将同时通过他。不过,我不知道它会对这种行为做出什么反应。

我可以使用一些技巧和提示来正确执行这一操作。提前谢谢。

使用多个SQL连接

我想做一个巨大的SQL语句,将所有需要的SQL表连接到一个命令中

可能不是一个好主意,因为你提到的原因——你要求的数据比必要的多得多。此外,每次您的数据模式更改时,您都必须维护该语句

我正在考虑创建一个全局SqlConnection变量,该变量将只初始化一次,并且我的所有SQL查询都将同时通过他。

再说一遍,这不是一个好主意。SQL连接是池化的,因此创建它们通常不太昂贵。此外,"全局"变量可以降低可测试性,并为设计添加不易删除的依赖项。

您的模式对于低级SQL存储库来说非常典型。一般模式是:

  1. 生成SQL语句
  2. 创建/打开连接
  3. 创建SQL命令
  4. 执行SQL命令
  5. 将结果转换为数据结构(DataTable/对象集合)
  6. 返回数据结构

可以修改代码以启用一些重用,但这大约是您能得到的最低值,因为每个SQL命令都不同,可能需要特殊处理(参数、事务等)

此外,拥有多个专用SQL语句也有一些优点,包括:

  • 效率-只要求提供所需的数据
  • 隔离-如果更改一个表的模式,则只需更改直接受影响的命令
  • 模块化-如果需要,更改一个实体的来源会更简单

根据评论进行编辑

听起来你看到的是两个极端——一端是分别提取每个对象(10个查询),另一端是提取所有对象并仔细选择要保留的数据。可能有时您希望一次提取几个表,这对于SQL语句来说很容易实现,而不需要所有查询都使用一个单一的SQL语句。

例如,一个查询连接UserAccountUserAddress,然后根据结果创建多个对象。这是完全有效的,并且可以使用您正在使用的模式来完成,而不需要一个巨大的查询来提取所有可能的数据。

像EntityFramework这样的ORM一直都在做这类事情,但当它进入实际的数据库连接时,它使用的模式与您正在使用的模式类似——创建连接、创建命令、执行它、合并结果、关闭连接。

您正在做的事情看起来像Linq给您的东西,主要区别在于没有"Live"数据库查询支持的属性,而是一种一次性在内部填充所有属性的方法。

我建议您仔细查看现有的框架,如Linq-to-SQL或Linq-to-Entities(实体框架)