1

I want to read all records from "product" table and create objects from each records. it only gets one records from the database, any ideas might help ?

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;
        };
    }
}
3
  • 1
    Why needed reader.NextResult();? You have while loop on reader.Read(). Commented Oct 21, 2021 at 14:56
  • You needn't it. reader.Read() switches to next record and returns true if next record exists. Otherwise false, which means there no more records to read. Commented Oct 21, 2021 at 14:58
  • If I get rid of it, this error occur : Unable to cast object of type 'System.DBNull' to type 'System.String. Commented Oct 21, 2021 at 14:59

4 Answers 4

1

If you have several result sets, you should loop over them, i.e. you should put one more outer loop, e.g.

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());

Note outer do .. while loop since we always have at least one result set.

Sign up to request clarification or add additional context in comments.

1 Comment

YES, thank you this works perfectly !
1

You use NextResult which advances the reader to the next result set. This makes sense if you have multiple sql queries and you'd use it after the while-loop. Here it's just unnecessary and wrong.

You are already advancing the reader to the next record with Read.

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

You can use 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);

Use it for every nullable column, for the numeric columns you could use nullable types like int?.

Comments

0

You have an error in your code: Remove the line reader.NextResult();

NextResult is used for moving to next result set not next record.

Comments

0

Definitely remove the NextResult(). That does NOT move between individual records in the same query. Read() does this for you already. Rather, NextResult() allows you to include multiple queries in the same CommandText and run them all in one trip to the database.

Try this:

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;
            }
        }
    }
}

2 Comments

okey, I removed it but still "Unable to cast object of type 'System.DBNull' to type 'System.String" error occurs.
Then you need to add code to the new Product() section to look for those NULL values. Also, the Price value should be decimal rather than double. NEVER use double for money.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.