简体   繁体   中英

What is the best way to transfer data from SqlDataReader into List<SomeClass>?

Code below is me trying to do just that. It returns all rows but only like DEFAULT VALUES (0, empty string, empty date...) and "Allow Nulls" is false for all columns in my db table. I am truly stuck. I am still in process of learning c#, so if someone could please explain to me WHAT am I doing wrong here? Is there a better way to do this?

   public List<XNarudzbe> GetXNarudzbe()
        {
            var listXnar = new List<XNarudzbe>();

            using (SqlConnection NConnection = new SqlConnection(Params.ConnectionStr))
            {
                NConnection.Open();
                using (var cmd = new SqlCommand("SELECT * FROM [dbo].[XDATA_NARUDZBE]", NConnection))
                {
                    SqlDataReader reader = cmd.ExecuteReader();

                    int id = reader.GetOrdinal("ID");
                    int dt_get = reader.GetOrdinal("DT_GET");
                    int rn_datum = reader.GetOrdinal("RN_DATUM");
                    int datum = reader.GetOrdinal("DATUM");
                    int dt_stamp = reader.GetOrdinal("DT_STAMP");
                    int art_id = reader.GetOrdinal("ART_ID");
                    int cijena_k = reader.GetOrdinal("CIJENA_K");
                    int cijena_mp = reader.GetOrdinal("CIJENA_MP");
                    int cijena_vp = reader.GetOrdinal("CIJENA_VP");
                    int faktura = reader.GetOrdinal("FAKTURA");
                    int isporuceno = reader.GetOrdinal("ISPORUCENO");
                    int iznos_k = reader.GetOrdinal("IZNOS_K");
                    int iznos_p = reader.GetOrdinal("IZNOS_P");
                    int naruceno = reader.GetOrdinal("NARUCENO");
                    int narudzba = reader.GetOrdinal("NARUDZBA");
                    int otpremnica = reader.GetOrdinal("OTPREMNICA");
                    int pdv = reader.GetOrdinal("PDV");
                    int povrat_k = reader.GetOrdinal("POVRAT_K");
                    int povrat_p = reader.GetOrdinal("POVRAT_P");
                    int pp_id = reader.GetOrdinal("PP_ID");
                    int preporuka = reader.GetOrdinal("PREPORUKA");
                    int rabat = reader.GetOrdinal("RABAT");
                    int rn_id = reader.GetOrdinal("RN_ID");
                    int skart = reader.GetOrdinal("SKART");
                    int user_id = reader.GetOrdinal("USER_ID");
                    int var_n = reader.GetOrdinal("VAR_N");
                    int var_v = reader.GetOrdinal("VAR_V");
                    int veleprodaja = reader.GetOrdinal("VELEPRODAJA");
                    int vraceno = reader.GetOrdinal("VRACENO");
                    int isporuka_id = reader.GetOrdinal("ISPORUKA_ID");
                    int otpremljeno = reader.GetOrdinal("OTPREMLJENO");
                    int promjena = reader.GetOrdinal("PROMJENA");
                    int rj_id = reader.GetOrdinal("RJ_ID");
                    int zakljucano = reader.GetOrdinal("ZAKLJUCANO");

                    if (reader.HasRows)
                    {
                        while (reader.Read())
                        {

                            var recXNar = new XNarudzbe();

                            recXNar.id = reader["ID"] as decimal? ?? 0M;    // reader.GetDecimal(id);
                            recXNar.dt_get = reader.GetDateTime(dt_get);
                            recXNar.rn_datum = reader.GetDateTime(rn_datum);
                            recXNar.datum = reader.GetDateTime(datum);
                            recXNar.dt_stamp = reader.GetDateTime(dt_stamp);
                            recXNar.art_id = reader.GetDecimal(art_id);
                            recXNar.cijena_k = reader.GetDecimal(cijena_k);
                            recXNar.cijena_mp = reader.GetDecimal(cijena_mp);
                            recXNar.cijena_vp = reader.GetDecimal(cijena_vp);
                            recXNar.faktura = reader.GetDecimal(faktura);
                            recXNar.isporuceno = reader.GetDecimal(isporuceno);
                            recXNar.iznos_k = reader.GetDecimal(iznos_k);
                            recXNar.iznos_p = reader.GetDecimal(iznos_p);
                            recXNar.naruceno = reader.GetDecimal(naruceno);
                            recXNar.narudzba = reader.GetDecimal(narudzba);
                            recXNar.otpremnica = reader.GetDecimal(otpremnica);
                            recXNar.pdv = reader.GetDecimal(pdv);
                            recXNar.povrat_k = reader.GetDecimal(povrat_k);
                            recXNar.povrat_p = reader.GetDecimal(povrat_p);
                            recXNar.pp_id = reader.GetDecimal(pp_id);
                            recXNar.preporuka = reader.GetDecimal(preporuka);
                            recXNar.rabat = reader.GetDecimal(rabat);
                            recXNar.rn_id = reader.GetDecimal(rn_id);
                            recXNar.skart = reader.GetDecimal(skart);
                            recXNar.user_id = reader.GetDecimal(user_id);
                            recXNar.var_n = reader.GetDecimal(var_n);
                            recXNar.var_v = reader.GetDecimal(var_v);
                            recXNar.veleprodaja = reader.GetDecimal(veleprodaja);
                            recXNar.vraceno = reader.GetDecimal(vraceno);
                            recXNar.isporuka_id = reader.GetString(isporuka_id);
                            recXNar.otpremljeno = reader.GetString(otpremljeno);
                            recXNar.promjena = reader.GetString(promjena);
                            recXNar.rj_id = reader.GetString(rj_id);
                            recXNar.zakljucano = reader.GetString(zakljucano);

                            listXnar.Add(recXNar);

                        }
                    }

                    reader.Close();
                }

            }
            return listXnar;
        }

There is a better way ( You need to just do it once and it will help in future). Derive a class from DbDataReader that will take sqldatareader in the constructor:

 public class CustomReader : DbDataReader
{
    private readonly SqlDataReader sqlDataReader;
    //Set the sqlDataReader
    public CustomReader(SqlDataReader sqlDataReader)
    {
        this.sqlDataReader = sqlDataReader;
        //Cache the names
        this.CacheColumns();
    }
    private Dictionary<string,int> nameOrdinals = new Dictionary<string, int>(); 
    private void CacheColumns()
    {
        int fieldCount= this.sqlDataReader.FieldCount;
        for (int i = 0; i <= fieldCount-1; i++)
        {
            string name=sqlDataReader.GetName(i);
            nameOrdinals.Add(name,i);
        }
    }

    public override object this[string name]
    {
        get
        {
            int ordinal=this.nameOrdinals[name];
            return this.GetValue(ordinal);
        }
    }
    //Custom implementation
    public string GetString(string name)
    {
        int ordinal = this.nameOrdinals[name];
        return this.GetString(ordinal);
    }
    //Custom implementation
    public string GetString(string name,string defaultValue)
    {
        int ordinal = this.nameOrdinals[name];
        if (this.IsDBNull(ordinal))
        {
            return defaultValue;
        }

        return this.GetString(ordinal);
    }

    //return from sqlDataReader
    public override string GetString(int ordinal)
    {
        return sqlDataReader.GetString(ordinal);
    }


    public override void Close()
    {
        sqlDataReader.Close();
    }

So what I have done is passed the SqlDataReader in custom class that can cache the column names with the positions. Then you are free to call the Custom implementation using the delegate sqldatareader or write your own functions on top - like I have done for string. Little bit of work initially but you can put all checks here like check for DbNull etc and return default values based on that.

 SqlCommand sqlCommand = new SqlCommand("select * from cats",sqlConnection);
        SqlDataReader reader = sqlCommand.ExecuteReader();
        CustomReader customReader = new CustomReader(reader);
        List<Cat> list = new List<Cat>();
        while (customReader.Read())
        {
            Cat cat = new Cat();
            cat.Id = customReader.GetString("id");
            cat.Name = customReader.GetString("name");
            list.Add(cat);    
        }

You may need to check the names of the columns coming back so may be store in lower case and then read in lower case. Your code doesnt need to do getordinal anymore and it is much cleaner as well.

There are several ways to do this using the SqlDataReader and DataTable....

        IEnumerable<DataRow> list0 = dt.AsEnumerable();

OR

        List<DataRow> list1 = new List<DataRow>(dt.Select());

OR

        List<DataRow> list2 = dt.AsEnumerable().ToList();

For simple examples of DataTable take a look at this.....

http://www.nakdev.somee.com/#2&2AD97ECBE2AE41D08191F6E4C773D8A9&cs

Well it turns out that the code in my first post is OK! The mistake was in my POCO definition.

This is what caused the problem :

...

private DateTime _dt_get;    

public DateTime dt_get
{
    get { return _dt_get; }
    set { value = _dt_get; }  // <-- !!! insted of set { _dt_get = value; }
}


...

Thx for any help...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM