Laden...

Mit Reflection Datenbankwerte lesen

Erstellt von Maendler53 vor 2 Jahren Letzter Beitrag vor 2 Jahren 405 Views
Maendler53 Themenstarter:in
5 Beiträge seit 2021
vor 2 Jahren
Mit Reflection Datenbankwerte lesen

Ein schönes Hallo an alle Experten

Ich programiere eine Klasse<T> (wobie T immer ein DataTrnsferObject ist) welech mir den Zugriff auf eine DB bezwecks eine derer Tabellen automatisiert und folgende Funktioenen beinhaltet: get ObservableCollection<T>, void T Insert(T item), void Update(T item) und void Delete(T item). Die Funktioen Inser, Update und Delete sind gelöst. Nur die Funktion get ObservableCollection<T> ist noch nicht zufriedenstellend glöst.

Nun zum Problem:
Um dem Item<T> Werte zu zuweisen benutze ich die Klasse BindItem nach dem Beispeil: Binder Class in welcher ich noch die nicht primitiven Typen implementiert habe.

Um die Daten von get ObservableCollection<T> aufzubereiten benuze ich den privaten void AddData().


private void AddData()
        {
            // Erzeugen des SelectSql
            // _tableInfos (readOnly) enthalten die ColumnIndexes und ColumnNames 
            // _parameterItem (readOnly) enthaletn: TableName, PropertyName (der Name der Property die bei GetMethod( Paramerer name benötigt wird) und die ParametetTypen

            var sb = new StringBuilder("SELECT ");
            foreach (var colInfo in _tableInfos) sb.Append($"{colInfo.ColunName}, ");
            sb.Remove(sb.ToString().Length - 2, 2);
            sb.Append($" FROM {_parameterItem.TableName}");


            // SqlComand erstellen
            using (var cmd = new SqlCommand(sb.ToString(), sqlConnection))
            {
                if (sqlConnection.State.Equals(ConnectionState.Closed)) sqlConnection.Open();

                
                using (var rdr = cmd.ExecuteReader())
                { 
                    // Daten aus Tebelle auslesen
                    while (rdr.Read())
                    {
                        var data = new object[_parameterItem.ParameterTypes.Length];

                        for (int i = 0; i < rdr.FieldCount; i++)
                        //for (int i = 0; i < 1; i++)
                        {
                            var obj = rdr.GetValue(i);

                            // Wenn Type von obj ungleich und PropertyType, ist der Typ von obj entsprechen zu wandeln
                            if (!itemInfos[i].PropertyType.Equals(obj.GetType()))
                            {
                                if (obj.GetType() == typeof(int)) obj = BooleanConverter.IntToBool((int)obj);
                                else if (obj.GetType() == typeof(decimal)) obj = Convert.ToDouble(obj);
                                else if (obj.GetType() == typeof(DBNull)) obj = null;
                                else throw new Exception("PropertyTypeException", new Exception("Der gewünschte Typ ist noch nicht implementier"));
                            }
                            data[i] = obj;
                        }

                        var instance = Activator.CreateInstance(typeof(T));

                        // GetMethod wirft keine Exception, sondern git null zurück
                        MethodInfo method = typeof(T).GetMethod(_parameterItem.PropertyName, BindingFlags.Public | BindingFlags.Instance, new BindItem(), _parameterItem.ParameterTypes, null);
                        // Wenn T = FoodDTO ist method nicht null, weil die Klasse SelectMethod ausgeführt wird.
                        // Wenn T = EmployerDTO ist method null, weil die Klasse SelectMethod nicht ausgeführt wird. Wobei _parameterItem.ParameterTypes auf ein Int32 reduziert wurde und die Funktion (AddItemValues) auch nur ein Parameter erwatet.

                        if (method.Equals(null)) throw new Exception("ParameterTypeExzeption", new Exception("Fehler bei der Ahnzal,  der ParameterTypen, oder Untiimmigkeiten zwischen dem parameterisierten Konstrucktor und den zu serialisierenden Parametertypen"));

                        method.Invoke(instance, BindingFlags.InvokeMethod, new BindItem(), data, CultureInfo.CurrentCulture);

                        observableCollection.Add((T)Convert.ChangeType(instance, typeof(T)));

                    }
                }

                if (sqlConnection.State.Equals(ConnectionState.Open)) sqlConnection.Close();

            }
        }

Ich hoffe das die Komentare im void AddDate() aussagekräftig genug sind.

Das DataTranserObject das mit nicht null ausgeführt wird:


 [Serializable]
    public class FoodDTO
    {
        public FoodDTO() { }

        public FoodDTO(int id, string name, bool isAvalaible)
        {
            ID = id;
            Name = name;
            IsAvalaible = isAvalaible;
        }

        public void AddItemValues(int id, string name, bool isAvalaible)
        {
            ID = id;
            Name = name;
            IsAvalaible = isAvalaible;
        }

        public int ID { get; set; }
        public string Name { get; set; }
        public bool IsAvalaible { get; set; }
        public static string PropertyName { get => "AddItemValues"; }
    }

Das DataTranserObject das mit null ausgeführt wird:


[Serializable]
    public class EmployerDTO : ICopy<EmployerDTO>
    {
        public EmployerDTO() { }

        public EmployerDTO(string fullName, string position, DateTime birstDay, double salery, string coment, string imagePaht = null, 
             int id = -1)
        {
            ID = id;
            EmployerName = fullName;
            Position = position;
            BirstDay = birstDay;
            Salery = salery;
            Coment = coment;

            if (imagePaht != null) Image = ConvertImagesToBytes.ConvertFromFilePath(imagePaht);
        }

        public void AddItemValues(int id)
        {
            ID = id;
            //EmployerName = fullName;
            //Position = position;
            //BirstDay = birstDay;
            //Salery = salery;
            //Coment = coment;
            //Image = imageBytes;
        }

        public int ID { get; set; }
        public string EmployerName { get; set; }
        public string Position { get; set; }
        public DateTime BirstDay { get; set; }
        public double Salery { get; set; }
        public string Coment { get; set; }
        public byte[] Image { get; private set; }
        public int Age { get => DateTime.Now.Year - BirstDay.Year; }
        public EmployerDTO GetCopy { get=> DeepCopy.Copy(this); }


        public override bool Equals(object obj)
        {
            return ID == (obj as EmployerDTO).ID;
        }

        public override int GetHashCode()
        {
            return ID.GetHashCode();
        }

        public static string GetPropertyName { get => "AddItemValues"; }
    }

Herzliche Grüsse aus der Schweiz Mäendler53

Maendler53 Themenstarter:in
5 Beiträge seit 2021
vor 2 Jahren
Ups

Ist wohl am falsechen Ort gelandet!

16.807 Beiträge seit 2008
vor 2 Jahren

Mir ist etwas unklar, warum Du das Rad neu erfinden willst. Das liest sich hier nicht raus.
Das, was Du da hast, verletzt durchaus einige Prinzipien, Code Pattern und Architektur Best Practises, zB. dass eine Datenschicht kein ObservableCollection liefert (weil man das ohnehin in der UI nicht neu binden sollte, sondern nur die Inhalte aktualisiert werden); oder auch dass Du bei jeder DB Operation ne eigene Verbindung aufbaust.

Warum machst Du das? Warum verwendest Du nicht einfach einen stabilen, existierenden ORM wie Entity Framework Core oder Dapper...?
Machst Dir so ja das Leben selbst schwer. Reflection ist zusätzlich noch die aller aller aller langsamste Variante, wie Du solch ein Vorhaben umsetzen kannst.

Ich hab aber Deinen Kommentaren nicht entnehmen können, was nun eigentlich das konkrete Problem ist.
In meinen Augen kann man aber das gesamte Problem lösen, in dem man so einen (eher als instabil zu bezeichneten) Code vermeidet und halt direkt mit ORMs und Best Practise Pattern (zB Projektionen) arbeitet.

Was mir direkt ins Auge gesprungen ist: Grundlagen zu DateTime.
Verwende kein DateTime, besonders nicht in Datenbanken! => [FAQ] DateTime vs. DateTimeOffset und der Umgang mit Zeiten in .NET.
Wenn Du auf der neuen .NET Plattform bist, kannst Du für Geburtstage einfach DateOnly verwenden (ist in der FAQ beschrieben).

PS: das sind keine Funktionen, das sind Methoden.
Funktionen in C# sind nach strenger Auslegung was anderes.

J
641 Beiträge seit 2007
vor 2 Jahren

Denke für einen Geburtstag ist DateTime okay, da ist die Zeitzone ja wirklich nicht relevant, da ja nur ein Datum gespeichert wird.
Aber DateOnly gibts im Moment ja nur in der Preview, daher würde ich das noch nicht einsetzen.

Aber ich würde dir auch empfehlen einen ORM Mapper zu nutzen. Ich kann da noch linq2db (GitHub - linq2db/linq2db: Linq to database provider.) empfehlen, liegt irgendwo zwischen dapper & ef-core.

Achso, es heist BirthDay nicht BirstDay & Comment mit 2 m

Ich weiß meine Rechtschreibung passt auch oft nicht, aber bei Variablennamen, da schau ich mehr drauf 😉

cSharp Projekte : https://github.com/jogibear9988

16.807 Beiträge seit 2008
vor 2 Jahren

Am korrektesten ist DateOnly und das Speichern des Geburtstags über drei Ganzzahlen.
-> DateTimeOffset hat eben die Zeitzone und Uhrzeit, die unnötig ist. Der Tag bleibt aber korrekt, wenn Du zB das Alter errechnen willst.
-> DateTime hat ein implizites Verhalten, weshalb Du wieder explizit programmieren musst, wenn Du das Alter errechnen willst.

Du siehst: auch für Geburtstage hat DateTime negative Nebeneffekte.
Es gibt wirklich kein Grund DateTime zu nutzen 🙂

A
764 Beiträge seit 2007
vor 2 Jahren

Hallo Maendler53

Deine konkrete Frage habe ich auf die Schnelle nicht gefunden. Wie ist die?

Abgesehen davon hat Abt schon alles gesagt. So was macht man auf keinen Fall selber, höchstens als Fingerübung, um es direkt danach weg zuwerfen.

Mir ist noch aufgefallen, dass du unglaublich viele Rechtsschreibfehler machst. Nicht nur in deinem Text, in dem fast jedes dritte Wort falsch ist, sondern auch im Code. Beispiele: 'birstDay', 'coment', 'imagePaht'. Wenn ich so was sehe, weiß ich sofort, dass ich es mit Larifari-Code zu tun habe. Geb dir da mehr Mühe, das ist eine Einstellungs-Sache.Bei der Rechtschreibung fängt es an. Legastenie ist da keine Ausrede. Verwende Tools um die Rechtschreibung zu checken und lese mehrmals, bis alles korrekt ist.

Herzliche Grüße
Alf