Krisztián's profileBátyai Krisztián[KRis]PhotosBlogListsMore Tools Help

Blog


    August 14

    SqlDataReader AsEnumberable() && LINQ

     

    Tartottam mostanában egy LINQ tanfolyamot, amit azzal kezdtem, hogy NEM tud a LINQ semmi olyat amit az eddigi technológiák, módszerek ne tudtak volna...DE ez nem azt jelenti hogy egy teljesen felesleges valami, hanem CSAK annyit jelent, hogy máshogy, más szemlélettel, egyszerűbben tudunk bizonyos problémákat megoldani...

    Van 'jópár új eszközünk amit ha megfelelően kombinálunk egészen jó dolgok sülnek ki belőle...

    Ilyen kombináció a IEnumberable/yield return - LINQ query expression - object/collection initializer kombináció.

    Lássunk egy megszokott 2.0-s megoldást egy file-ból olvasásra:

    Adatfile :

    1;Alma;piros;100
    2;Korte;;200
    3;Barack;kajszi;300
    4;Barack;őszi;400

    Üzleti objektum:

    public class Product
    {
        public int ID { get; set; }
        //auto implemented property
        public string Name { get; set; }
        public string Description { get; set; }
        public int Price { get; set; }
    }

    Felolvasás:

    StreamReader sr = new StreamReader("data.txt");
    
    List<Product> lst2dot0 = new List<Product>();
    Product actP;
    string line;
    while (!sr.EndOfStream)
    {
        line = sr.ReadLine();
        actP = new Product();
        actP.ID = int.Parse(line.Split(';')[0]);
        actP.Name = line.Split(';')[1];
        actP.Description = line.Split(';')[2];
        actP.Price = int.Parse(line.Split(';')[3]);
        lst2dot0.Add(actP);
    }

    Sok a felesleges kód...

    Nézzünk ezt c#3.0 -val:

    StreamReader sr = new StreamReader("data.txt"); 
    var
    lstProds = sr.AllLines().Select(line2 => line2.Split(';')) .Select(cols => new Product() { ID = int.Parse(cols[0]), Name = cols[1], Description = cols[2], Price = int.Parse(cols[3]) });

    No de mi az az AllLines() a StreamReaderen?!?! Hát kérem ExtensionMethod...

    public static class MyExt
     {
         public static IEnumerable<string> AllLines(this StreamReader stream)
         {
             string line;
             while ((line = stream.ReadLine()) != null)
             {
                 //Console.WriteLine("\t Allines olvasta : " + line);
                 yield return line;
             }
         }
     }

    Egyszerű, mégis nagyszerű!!!

    Nézzük ugyan ezt adatbázisból, 2.0:

    Adatbázis AdwentureWorks, üzleti objektum Production.Product:

    public class Product
    {
        public int ID { get; set; }
        public string Name { get; set; }
            
        public bool OwnProperty { get; set; }
    } 

    Beolvasás:

    using (SqlConnection conn = new SqlConnection(scsb.ConnectionString))
           {
               conn.Open();
    
               SqlCommand cmd = new SqlCommand();
               cmd.Connection = conn;
               cmd.CommandText = "select top 5 * from Production.Product";
    
               Product actP;
    
               List<Product> lstP_foreach = new List<Product>();
               //ciklus a termékeken
               using(SqlDataReader rd = cmd.ExecuteReader())
               {
                   while (rd.Read())
                   {
                       actP = new Product();
                       actP.ID = (int)rd["ProductID"];
                       actP.Name = rd["Name"].ToString();
    
                       //sajat propertyk allitasa
                       actP.OwnProperty = actP.ID % 2 == 0;
    
                       //listahoz adas
                       lstP_foreach.Add(actP);
    
                   }
                }

    }

    Ugyan ez c# 3.0-val és LINQ-el:

    using (SqlConnection conn = new SqlConnection(scsb.ConnectionString))
              {
                  conn.Open();
    
                  SqlCommand cmd = new SqlCommand();
                  cmd.Connection = conn;
                  cmd.CommandText = "select top 5 * from Production.Product";
    
                  Product actP;
    
                  List<Product> lstP_foreach = new List<Product>();
                  //ciklus a termékeken
                  using(SqlDataReader rd = cmd.ExecuteReader())
                  {
                     var lstP_linq = from row in rd.AsEnumerable()
                                      select new Product()
                                      {
                                          ID = (int)row["ProductID"],
                                          Name = row["Name"].ToString(),
                                          OwnProperty = (int)row["ProductID"] % 2 == 0
                                      };
                  }
    }

    No és itt vajon mi az AsEnumberable()?!?

    Gondolom kitalálható...

    public static class SqlDataReaderEXT
    {
        public static IEnumerable<Dictionary<string,object>> AsEnumerable(this SqlDataReader rd)
        {
            while (rd.Read())
            {
                Dictionary<string, object> ret = new Dictionary<string,object>();
    
                for (int i = 0; i < rd.FieldCount; i++)
                {
                    ret.Add(rd.GetName(i),rd[i]);                    
                }
                yield return ret;
            }
        }
    }

    Tualjdonképpen egy string-object Dictionary... Amiben KeyValuePair-ek lakoznak. Pont ami nekünk kell...
    Akinek ez nem tetszik, szabadon írhat saját osztályt az elemeknek...

     

    Persze meg kell jegyezni hogy nem találtam fel a spanyol viaszt, ez tulajdonképpen az eszközök megfelelő használata...
    Nem old meg eddig megoldatlan problémát, sőt nem is gyorsabb (bár nem is lassabb, de ez ugye relativ, ahol a nsec-ok is számítanak...). Csak egy kicsit más a szemlélet, és talán tömörebb, érthetőbb is.