使用 SqlDataReader 读取 sql table 中的所有记录

Read all record in sql table using SqlDataReader

我想从“产品”table 中读取所有记录并从每条记录创建对象。 它只从数据库中获取一条记录,有什么想法可以帮助吗?

public IReadOnlyList<Product> Search(string name)
{
    var result = new List<Product>();

    using (var conn = new SqlConnection(connectionString))
    {
        if (name == null)
        {
            var command = new SqlCommand("SELECT * FROM Product ", conn);
            conn.Open();

            using var reader = command.ExecuteReader();
            {
                    
            while (reader.Read())
            {
                var prod = new Product((int)reader["ID"], (string)reader["Name"],
                    (double)reader["Price"], (int)reader["Stock"], (int)reader["VATID"],
                    (string)reader["Description"]);

                result.Add(prod);
                reader.NextResult();

            }
            reader.Close();
            conn.Close();
            return result;
        };
    }
}

您的代码有错误: 删除行 reader.NextResult();

NextResult 用于移动到下一个结果集而不是下一个记录。

您使用 NextResult 将 reader 推进到下一个结果集。如果您有多个 sql 查询并且您将在 while 循环之后使用它,那么这很有意义。这里只是不必要和错误的。

您已经将 reader 推进到下一个 记录 Read

If I get rid of it, this error occur : Unable to cast object of type 'System.DBNull' to type 'System.String.

您可以使用 IsDBNull:

int nameIndex = reader.GetOrdinal("Name");
string name = reader.IsDBNull(nameIndex) ? null : reader.GetString(nameIndex);
int descIndex = reader.GetOrdinal("Description");
string description = reader.IsDBNull(descIndex) ? null : reader.GetString(descIndex);

var prod = new Product((int)reader["ID"], 
                       name, 
                       (double)reader["Price"], 
                       (int)reader["Stock"], 
                       (int)reader["VATID"], 
                       description);

将它用于每个可为空的列,对于数字列,您可以使用像 int?.

这样的可为空的类型

绝对删除NextResult()。这确实 NOT 在同一查询中的各个记录之间移动。 Read() 已经为您完成了。相反,NextResult() 允许您在同一个 CommandText 和 运行 中包含多个查询,一次访问数据库。

试试这个:

public IEnumerable<Product> Search(string name)
{
    using (var conn = new SqlConnection(connectionString))
    using (var command = new SqlCommand("SELECT * FROM Product ", conn))
    {
        if (!string.IsNullOrEmpty(name) )
        {
           command.CommandText += " WHERE Name LIKE @Name + '%'";
           command.Parameters.Add("@Name", SqlDbType.NVarChar, 50).Value = name;
        }

        conn.Open();
        using var reader = command.ExecuteReader();
        {                    
            while (reader.Read())
            {
                var prod = new Product((int)reader["ID"], reader["Name"].ToString(),
                    (double)reader["Price"], (int)reader["Stock"], (int)reader["VATID"],
                    reader["Description"].ToString());

                yield return prod;
            }
        }
    }
}

如果你有几个个结果集,你应该循环它们,也就是说你应该再放一个外层循环,例如

using var reader = command.ExecuteReader();

do {
  while (reader.Read()) {
    var prod = new Product(
      Convert.ToInt32(reader["ID"]), 
      Convert.ToString(reader["Name"]),
      Convert.ToDouble(reader["Price"]), // decimal will be better for money
      Convert.ToInt32(reader["Stock"]), 
      Convert.ToInt32(reader["VATID"]),
      Convert.ToString(reader["Description"])
    );

    result.Add(prod); 
  }
}
while (reader.NextResult());

注意外部 do .. while 循环,因为我们总是至少有一个结果集。