Avatar billede lasserasch Juniormester
30. november 2009 - 01:09 Der er 15 kommentarer og
1 løsning

Hjælp til at bygge en generisk SQL Commit Metode.

Hejsa.

Jeg er ved at lave et lille forsøg og har brug for lidt hjælp.

Først lidt fakta:

1. Property navne på mine objekter er altid de samme som feltnavne i SQL databasen.

2. Kompleksibiliteten vil være forholdsvis simpel. Jeg er klar over at det her nok er en dårlig løsning til store komplekse databse setups.


Jeg forsøger at lave en metode som gerne skulle kunne være rimelig meget "Plug And Play". Altså en metode jeg gerne vil kunne genbruge på mange objekter uden at skulle skrive den om.

Mine objekter indeholder som regl kun Strings, Int's, Boolean's samt referencer til andre objekter.

Jeg har så lavet en metode som gennemløber alle properties for et objekt og gerne skulle kunne opbygge en SQL Query automatisk som kan opdatere min database.

Det er ikke testet endnu, men umiddelbart vil jeg mene at det skulle virke fint nu, så længe at der ikke er referencer til andre objekter som skal med i min query.

Men jeg er i tvivl omkring hvordan man ved gennemløb af properties på et objekt finder ud af hvilket andet objekt der er en reference til.

Jeg kan se der trækkes en bool værdi ud for hver property som fortæller mig om denne property er en objekt reference.

Men hvis denne værdi er TRUE så har jeg brug for at kunne gå ned på dette andet objekt og fremfinde værdien for den property som hedder "Id" (på det andet objekt). Id propertien findes altid på mine objekter og det er denne værdi jeg bruge i databasen til at gemme referencer mellem de forskellige data.


Puha, lang smørre. Håber jeg har gjort mig nogenlunde forståelig.

Jeg har vedhæftet den kode jeg har (og håber/forventer virker allerede nu. Bare uden at kunne håndtere properties som er objekt referencer)


Mvh.
Lasse


          public void Commit()
          {
              Type ObjectType = typeof(Player);
              string tblname = "tb_players";
              string query = string.Empty;
           

              System.Reflection.PropertyInfo[] propertyInfo = ObjectType.GetProperties();
              if (this.Id > 0)
              {
                  query = "update " + tblname + " ";
                  foreach (System.Reflection.PropertyInfo info in propertyInfo)
                  {
                      Type t = info.PropertyType;
                      string proptype = t.Name;

                      object val = info.GetValue(this, null);
                      switch (proptype)
                      {
                          case "String": query += "set " + info.Name + " = '" + val.ToString().Replace("'", "''") + "', "; break;
                          case "Int32": query += "set " + info.Name + " = " + (int)val + ", "; break;
                          case "Boolean": query += "set " + info.Name + " = " + Convert.ToInt32((bool)val) + ", "; break;
                      }
                  }
                  query = query.Remove(query.Length - 3, 2);
                  query += "where id = " + this.Id;
              }


              else
              {
                  query = "insert into " + tblname + " (";
                  foreach (System.Reflection.PropertyInfo info in propertyInfo)
                  {
                      query += info.Name + ", ";
                  }

                  query += ") Values (";
                  foreach (System.Reflection.PropertyInfo info in propertyInfo)
                  {
                      Type t = info.PropertyType;
                      string proptype = t.Name;

                      object val = info.GetValue(this, null);
                      switch (proptype)
                      {
                          case "String": query += "'" + val.ToString().Replace("'", "''") + "', "; break;
                          case "Int32": query += (int)val + ", "; break;
                          case "Boolean": query += Convert.ToInt32((bool)val) + ", "; break;
                      }
                      query += ")";
                  }
              }


              /// Execute Query to SQL Database here...
          }
Avatar billede arne_v Ekspert
30. november 2009 - 01:14 #1
Du laver vel en default label paa din switch hvor du bruger reflection paa val objektet til at hente id med. Typens navn har du allerede.
Avatar billede lasserasch Juniormester
30. november 2009 - 01:18 #2
?? Det forstår jeg ikke helt. Kan du komme med et kort eksempel?

Mvh.
Lasse
Avatar billede lasserasch Juniormester
30. november 2009 - 01:34 #3
Mener du noget ala det her:

switch (proptype)
                      {
                          case "String": query += "set " + info.Name + " = '" + val.ToString().Replace("'", "''") + "', "; break;
                          case "Int32": query += "set " + info.Name + " = " + (int)val + ", "; break;
                          case "Boolean": query += "set " + info.Name + " = " + Convert.ToInt32((bool)val) + ", "; break;
                          default:
                              if (t.IsClass)
                              {
                                  System.Reflection.PropertyInfo pinfo = t.GetProperty("Id");
                                  query += "set " + info.Name + " = " + (int)pinfo.GetValue(pinfo, null) + ", ";
                              }
                              break;
                      }
Avatar billede arne_v Ekspert
30. november 2009 - 01:35 #4
utestet:

                      object val = info.GetValue(this, null);
                      switch (proptype)
                      {
                          case "String": query += "'" + val.ToString().Replace("'", "''") + "', "; break;
                          case "Int32": query += (int)val + ", "; break;
                          case "Boolean": query += Convert.ToInt32((bool)val) + ", "; break;
                          default:
                              int id = (int)val.GetType().GetProperty("Id").GetValue(val, null);
                              // goer noget med id her
                              break;
                      }
Avatar billede arne_v Ekspert
30. november 2009 - 01:36 #5
yes yes
Avatar billede lasserasch Juniormester
30. november 2009 - 01:42 #6
Super :-) Prøver... Smid svar, så lukker vi.

Takker.

Mvh.
Lasse
Avatar billede arne_v Ekspert
30. november 2009 - 02:02 #7
OK
Avatar billede arne_v Ekspert
30. november 2009 - 02:03 #8
OK
Avatar billede lasserasch Juniormester
30. november 2009 - 02:50 #9
Det virker ret godt..

Jeg smider lige hele metoden ind i tråden hvis andre skulle være interesseret i at se hvordan det kan laves.

Mvh.
Lasse




public void Commit()
        {
            // Specify Name of SQL Table
            string tblname = "tb_players";
           
            // Empty Params used in Method.
            string query = string.Empty;
            string classes = string.Empty;

            // Set witch class references should be written to DB.
            classes = "Company;Phonenumbers";


            System.Reflection.PropertyInfo[] propertyInfo = this.GetType().GetProperties();
            /// If Id Property of current Object is higher than 0 then build and update query.
            if (this.Id > 0)
            {
                query = "update " + tblname + " set ";

                /// Loop all properties of object.
                foreach (System.Reflection.PropertyInfo info in propertyInfo)
                {
                    Type t = info.PropertyType;
                    string proptype = t.Name;

                    object val = info.GetValue(this, null);
                    switch (proptype)
                    {
                        case "String":  query += info.Name + " = '" + val.ToString().Replace("'", "''") + "', "; break;
                        case "Int32":  query += info.Name + " = " + (int)val + ", "; break;
                        case "Boolean": query += info.Name + " = " + Convert.ToInt32(Convert.ToBoolean(val.ToString())) + ", "; break;
                        default:
                            if (t.IsClass)
                            {

                                if (classes != string.Empty && classes.Contains(info.Name.ToLower()))
                                {
                                    int id = (int)val.GetType().GetProperty("id").GetValue(val, null);
                                    query += "set " + info.Name + " = " + id + ", ";
                                }
                            }
                            break;
                    }
                }
                query = query.Remove(query.Length - 2, 1);
                query += "where id = " + this.Id;
             
            }

               
            else
            {
                /// Id property of this object is 0. Therefore asume that we want to insert a new record in the DB.
                query = "insert into " + tblname + " (";

                /// Loop all properties of object.
                foreach (System.Reflection.PropertyInfo info in propertyInfo)
                {
                    if (info.PropertyType.IsClass && info.PropertyType.Name != "String")
                    {
                        if (classes != string.Empty && classes.Contains(info.Name))
                            query += info.Name + ", ";
                    }
                    else
                        query += info.Name + ", ";
                }
                query = query.Remove(query.Length - 2, 2);

                query += ") Values (";

                /// Loop all properties of object.
                foreach (System.Reflection.PropertyInfo info in propertyInfo)
                {
                    object val = info.GetValue(this, null);
                    switch (info.PropertyType.Name)
                    {
                        case "String": query += "'" + val.ToString().Replace("'", "''") + "', "; break;
                        case "Int32": query += (int)val + ", "; break;
                        case "Boolean": query += Convert.ToInt32((Boolean)val) + ", "; break;
                        default:
                            if (info.PropertyType.IsClass)
                            {
                                if (classes != string.Empty && classes.Contains(info.Name))
                                {
                                    int id = (int)val.GetType().GetProperty("id").GetValue(val, null);
                                    query += id.ToString() + ", ";
                                }
                            }
                            break;
                    }
                }
                query = query.Remove(query.Length - 2, 2);
                query += ")";

            }

            /// Now Do something with the 'query' string object.
         
        }
Avatar billede windcape Praktikant
30. november 2009 - 04:28 #10
Er det rent akademisk?

Fordi prepared-statements gør jo præcis dette her :)
Avatar billede arne_v Ekspert
30. november 2009 - 04:37 #11
Så vidt jeg kan vurdere er det en ORM uden nogen former for konfiguration hverken XML, attributter eller genereret kode han er ved at lave (ved at bruge konventioner for klasserne og databasen).
Avatar billede lasserasch Juniormester
30. november 2009 - 11:14 #12
Prepared statements aner jeg ikke hvad er. Men det må jeg da have undersøgt :-)

Grunden til at jeg godt kunne tænke mig funktionen er for at få en Database Commit metode som er generisk og kan bruges på alle de klasser jeg laver og i forskellige projekter uden at jeg skal skrive SQL koden manuelt for hver klasse.

Og der må ikke skulle ændres mere end 1 - 2 variabler. For så tager det for lang tid at implementere.

Og den løsning jeg har fået skrevet nu ser ud til at opfylde de krav.

Så må vi jo så se om det er til at arbejde med i praksis.

:-)

Mvh.
Lasse
Avatar billede arne_v Ekspert
30. november 2009 - 14:40 #13
Prepared statements er det man kalder parameters udenfor MS verdenen.
Avatar billede windcape Praktikant
01. december 2009 - 17:12 #14
> Grunden til at jeg godt kunne tænke mig funktionen er for at få
> en Database Commit metode som er generisk og kan bruges på alle
> de klasser jeg laver og i forskellige projekter uden at jeg skal
> skrive SQL koden manuelt for hver klasse.

Lyder meget ala. ORM eller ActiveRecord. Tag et kig på Entity Framework (tidligere kendt som Linq2SQL), og nHibernate.
Avatar billede windcape Praktikant
01. december 2009 - 17:14 #15
> Prepared statements er det man kalder parameters udenfor MS verdenen.

Det hedder da også prepareStatement() i JDBC, og prepare() i PHP.

Men kært barn har mange navne :p
Avatar billede Syska Mester
01. december 2009 - 17:24 #16
ja, og det er vel også udenfor MS verdenen eller ?

Eller hvad er det du henviser til ... kan ikke lige se sammenhængen.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester