2

I'm trying to get all data from an SQL table and store it in a List using the C# programming language.

the SQL statement I'm using is:

private string cmdShowEmployees = "SELECT * FROM Employees;";

This is being used in the same class as a function

public List<string> showAllIdData()
{
  List<string> id = new List<string>();
  using (sqlConnection = getSqlConnection())
  {
    sqlCommand.Connection = sqlConnection;
    sqlCommand.CommandText = cmdShowEmployees;
    SqlDataReader reader = sqlCommand.ExecuteReader();
    while (reader.Read()) {
      id.Add(reader[0].ToString());
    }
    return id;
  }
}

and here

public List<string> showAllActiveData()
{
  List<string> active = new List<string>();
  using (sqlConnection = getSqlConnection())
  {
    sqlCommand.Connection = sqlConnection;
    sqlCommand.CommandText = cmdShowEmployees;
    SqlDataReader reader = sqlCommand.ExecuteReader();
    while (reader.Read()) {
      active.Add(reader[1].ToString());
    }
    return active;
  }

I would have to create 9 more functions this way in order to get all the data out of the Employees table. This seems very inefficient and I was wondering if there was a more elegant way to do this.

I know using an adapter is one way to do it but I don't think it is possible to convert a filled adapter to a list, list list etc.

SqlDataAdapter adapter = sqlDataCollection.getAdapter();
DataSet dataset = new DataSet();
adapter.Fill(dataset, "idEmployees");
dataGridView1.DataSource = dataset;
dataGridView1.DataMember = "idEmployees";

Any ideas?

thanksd
  • 54,176
  • 22
  • 157
  • 150
Brian Cotton
  • 23
  • 1
  • 1
  • 4
  • Is there a specific reason you need a *separate* List for each column? – Alex K. Jan 14 '16 at 14:22
  • Just fill a `DataTable` and use that as `DataSource` for a `BindingSource` that is the `DataSource` of the `DataGridView`. – Tim Schmelter Jan 14 '16 at 14:24
  • If I can use 1 list and get all columns and rows in an organized way then that would be great! The reason I separate the list for each column is because reader[x] only pulls 1 column. I've thought about doing List> but I am unsure how that would work once I return the data. – Brian Cotton Jan 14 '16 at 14:30
  • @TimSchmelter This is a great idea but I've separated my classes in such a way that this wouldn't make sense. This class is specific to sending sqldata and retrieving sqldata. If I start using Datasource/BindingSource as a solution then my class wouldn't make sense to me anymore. – Brian Cotton Jan 14 '16 at 14:41

3 Answers3

5

If you must use the reader in this way, why not create an object which holds the table row data.

public class SomeComplexItem
{
    public string SomeColumnValue { get; set;}
    public string SomeColumnValue2 { get; set;}
    public string SomeColumnValue3 { get; set;}
    public string SomeColumnValue4 { get; set;}
}

That way you can loop through with your reader as follows:

public List<SomeComplexItem> showAllActiveData()
{
    List<SomeComplexItem> active = new List<SomeComplexItem>();
    using (sqlConnection = getSqlConnection())
    {
        sqlCommand.Connection = sqlConnection;
        sqlCommand.CommandText = cmdShowEmployees;
        SqlDataReader reader = sqlCommand.ExecuteReader();
        while (reader.Read())
        {
            var someComplexItem = new SomeComplexItem();
            someComplexItem.SomeColumnValue = reader[1].ToString();
            someComplexItem.SomeColumnValue2 = reader[2].ToString();
            someComplexItem.SomeColumnValue3 = reader[3].ToString();

            active.Add(someComplexItem);
        }
        return active;

    }
Howard F
  • 138
  • 12
KevDev
  • 336
  • 1
  • 8
  • I feel dumb, thanks for the help. This will work! :) When you say "if you must use the reader in this way" are you suggesting that this way is somehow flawed? If that is the case what would be (in your opinion) a less flawed way? – Brian Cotton Jan 14 '16 at 14:44
  • No, not flawed. There are so many ways to do this. DataTables, Object relational mappers like Entity Framework etc.. This solution you have is perfectly acceptable. Only if you need to do this a lot, then I would consider approaching this differently. :) – KevDev Jan 14 '16 at 14:57
  • Nope its just for 1 table. I will however be executing the command many times. I don't think that will be an issue however (the table at most will consist of maybe 1000 employees). Again thanks for the help. You da best :) – Brian Cotton Jan 14 '16 at 16:13
0

You could use two select statements to populate two List<string> as shown in the example below where the key between reads is reader.NextResult();.

The database used is the standard Microsoft NorthWind database.

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;

namespace SQL_Server_TwoList
{
    public class DataOperations
    {
        public List<string> Titles { get; set; }
        public List<string> Names { get; set; }

        /// <summary>
        /// Trigger code to load two list above
        /// </summary>
        public DataOperations()
        {
            Titles = new List<string>();
            Names = new List<string>();
        }
        public bool LoadData()
        {
            try
            {
                using (SqlConnection cn = new SqlConnection(Properties.Settings.Default.ConnectionString))
                {
                    string commandText = @"
                    SELECT [TitleOfCourtesy] + ' ' + [LastName] + ' ' + [FirstName] As FullName FROM [NORTHWND.MDF].[dbo].[Employees]; 
                    SELECT DISTINCT [Title] FROM [NORTHWND.MDF].[dbo].[Employees];";

                    using (SqlCommand cmd = new SqlCommand(commandText, cn))
                    {

                        cn.Open();

                        SqlDataReader reader = cmd.ExecuteReader();

                        // get results into first list from first select
                        if (reader.HasRows)
                        {
                            while (reader.Read())
                            {
                                Names.Add(reader.GetString(0));
                            }

                            // move on to second select
                            reader.NextResult();

                            // get results into first list from first select
                            if (reader.HasRows)
                            {
                                while (reader.Read())
                                {
                                    Titles.Add(reader.GetString(0));
                                }
                            }
                        }
                    }
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}

Form code

namespace SQL_Server_TwoList
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            DataOperations dataOps = new DataOperations();
            if (dataOps.LoadData())
            {
                listBox1.DataSource = dataOps.Names;
                listBox2.DataSource = dataOps.Titles;
            }
        }
    }
}
Karen Payne
  • 4,341
  • 2
  • 14
  • 31
0

You could always add it all to a dataset or datatable instead of looping through using datareader to add to an array, dataset allows you to access data in similar way to array anyway.

        Connstr = "Data Source = " + SelectedIP + "; Initial Catalog = " + dbName + "; User ID = " + txtUsername.Text +"; Password = "+ txtPassword.Text +"";
        conn = new SqlConnection(Connstr);
        try
        {
            string contents = "SELECT * FROM ..."
            conn.Open();
            SqlDataAdapter da_1 = new SqlDataAdapter(contents, conn);   //create command using contents of sql file
            da_1.SelectCommand.CommandTimeout = 120; //set timeout in seconds

            DataSet ds_1 = new DataSet(); //create dataset to hold any errors that are rturned from the database

            try
            {
                //manipulate database
                da_1.Fill(ds_1);

                if (ds_1.Tables[0].Rows.Count > 0) //loop through all rows of dataset
                {
                   for (int i = 0; i < ds_1.Tables[0].Rows.Count; i++)
                    {
                                            //rows[rownumber][column number/ "columnName"]
                        Console.Write(ds_1.Tables[0].Rows[i][0].ToString() + " ");
                    }
                }
             }
             catch(Exception err)
             {}
         conn.Close();
      }
      catch(Exception ex)
      {}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
st3_121
  • 32
  • 6