Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 6 sur 6
  1. #1
    Membre habitué
    Inscrit en
    mars 2007
    Messages
    114
    Détails du profil
    Informations forums :
    Inscription : mars 2007
    Messages : 114
    Points : 101
    Points
    101

    Par défaut Ajouter des éléments à une liste par reflection

    Bonjour,

    j'essai d'initialiser une instance de classe à l'aide de la reflection.
    Pour cela j'ai pris soin de nommer et typer les propriété de la classe du même noms et types que les colonnes de la table.

    Cela fonctionne parfaitement pour les types simples. Par contre j'ai du mal à populer les listes.

    voici mon code:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
        public class Calendar : Root
        {
            protected string _CalendarName;
     
            // Properties
            public string CalendarName { get { return _CalendarName; } }
            public List<string> SubCal { get; set; }
            public List<DateTime> Holidays { get; set; }
     
            // Constructor
            public Calendar(string name) 
            {
                Dictionary<string, Object> keys = new Dictionary<string, Object>();
                keys.Add("CalendarName", name);
                loadFromDB("subcalendar", keys);
                loadFromDB("calendarview", keys);
            }
        }
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
     
        public class Root
        {
            private string _connectionString;
     
            public Root()
            {
                string bdd = ConfigurationManager.AppSettings["BDD"];
                _connectionString = ConfigurationManager.ConnectionStrings[bdd].ConnectionString;
            }
     
            private string buildClause(KeyValuePair<string, Object> kvp)
            {
                PropertyInfo prop = this.GetType().GetProperty(kvp.Key);
                string clause = "";
                string typeName = this.GetType().GetProperty(kvp.Key).PropertyType.Name;
     
                switch (typeName)
                {
                    case "String":
                        clause = kvp.Key + " = '" + Convert.ToString(kvp.Value) + "'";
                        break;
                    case "Boolean":
                        clause = kvp.Key + " = " + (Convert.ToBoolean(kvp.Value) ? "true" : "false");
                        break;
                    case "DateTime":
                        clause = kvp.Key + " = '" + Convert.ToDateTime(kvp.Value).ToString("yyyy-MM-dd") + "'";
                        break;
                    default:
                        throw new UnknownTypeException("Unknown type : " + typeName);
                }
                return clause;
            }
     
            private object getValue(MySqlDataReader reader, Type type, int col)
            {
                switch (type.Name)
                {
                    case "String":
                        return reader.GetString(col);
                    case "DateTime":
                        return reader.GetDateTime(col);
                    case "Boolean":
                        return reader.GetBoolean(col);
                    default:
                        throw new UnknownTypeException("Unknown type : " + type.Name);
                }
            }
     
            public void loadFromDB(string tableName, Dictionary<string, Object> keys)
            {
                // Build SQL request from parameters
                string sql = "select * from " + tableName;
                bool first = true;
     
                foreach (KeyValuePair<string, Object> kvp in keys)
                {
                    sql += (first ? " where " : " and ") + buildClause(kvp);
                    first = false;
                }
     
                // Execute sql request
                MySqlConnection myConnection = new MySqlConnection(_connectionString);
                MySqlCommand myCommand = myCommand = new MySqlCommand(sql, myConnection);
                myConnection.Open();
                MySqlDataReader reader = myCommand.ExecuteReader();
     
                // Parse result
                if (reader.HasRows)
                {
                    // Here we know there is at least one row
                    // First get the objects property
                    PropertyInfo[] props = this.GetType().GetProperties();
                    // The dictionnary will store the corresponding column number in the reader result
                    Dictionary<PropertyInfo, int> columns = new Dictionary<PropertyInfo, int>();
     
                    // Parse the properties to get the corresponding column number
                    foreach (PropertyInfo prop in props)
                    {
                        try
                        {
                            // Store the pair in the dictionnary
                            columns.Add(prop, reader.GetOrdinal(prop.Name));
                        }
                        catch (IndexOutOfRangeException e)
                        {
                            // current property does exist as column is this table
                            // ignore this error
                        }
                    }
     
                    // For each result row
                    while (reader.Read())
                    {
                        // Parse the properties to fetch them from reader data
                        foreach (KeyValuePair<PropertyInfo, int> column in columns)
                        {
                            // get the property type
                            Type type = column.Key.PropertyType;
                            // Check if it is a List
                            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
                            {
                                // Get the list item type
                                Type itemType = type.GetGenericArguments()[0];
                                // Get the list to add the value
                                var col = column.Key.GetValue(this, null) as IList;
                                if (col != null) // --> col is always null 
                                    col.Add(getValue(reader, itemType, column.Value));
                                else
                                    throw new InvalidOperationException("Not a list");
                            }
                            else
                            {
                                // If not just fetch the property or the corresponding field
                                if (column.Key.CanWrite)
                                    column.Key.SetValue(this, getValue(reader, type, column.Value), null);
                                else
                                    this.GetType().GetField("_" + column.Key.Name, BindingFlags.NonPublic | BindingFlags.Instance).SetValue(this, getValue(reader, type, column.Value));
                            }      
     
                        }
                    }
                }
            }
        }
    }
    et enfin le contenu des tables pour un calendrier

    subcalendar:
    CalendarName SubCal
    000 London
    000 New-York

    calendarview:
    CalendarName Holidays
    000 05/11/2013
    000 04/07/2013

    Malheureusement, dans le la classe Root, je n'arrive pas à récupérer l'instance de List pour y ajouter un élément. J'obtiens toujours un pointeur null.

    une idée pour me dépanner ?

  2. #2
    Membre éprouvé

    Profil pro
    Inscrit en
    juin 2002
    Messages
    311
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : juin 2002
    Messages : 311
    Points : 410
    Points
    410

    Par défaut

    Laisse-moi reformuler.

    Tu veux prendre un résultat brut sous forme de Resultset d'ADO.Net et créer une instance d'une classe en faisant la correspondance entre les propriétés de cette classe et le nom des colonnes dans le dataset?

  3. #3
    Membre habitué
    Inscrit en
    mars 2007
    Messages
    114
    Détails du profil
    Informations forums :
    Inscription : mars 2007
    Messages : 114
    Points : 101
    Points
    101

    Par défaut

    c'est tout à fait ça.

    La requête renvoie plusieurs car on veut ajouter à la liste correspondante (SubCal ou Holidays) la valeur de la colonne du même nom

  4. #4
    Membre éprouvé

    Profil pro
    Inscrit en
    juin 2002
    Messages
    311
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : juin 2002
    Messages : 311
    Points : 410
    Points
    410

    Par défaut

    Je n'ai pas de solution spécifique pour ce que tu veux faire, par contre voici une classe que j'ai faite pour adapter une instance de classe vers une nouvelle instance d'un type donné en faisant la correspondance entre les propriétés.

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    public static class Adapter
        {
            /// <summary>
            /// Generic converter that will create an instance of type and fill properties that share same name (not case sensitive)
            /// </summary>
            /// <typeparam name="T">The type of instance wanted</typeparam>
            /// <param name="entity">The entity to be converted</param>
            /// <returns></returns>
            public static T ConvertTo<T>(this object entity)
            {
     
                // Create return instance
                var newEntity = (T)Activator.CreateInstance(typeof(T));
     
                if (entity != null)
                {
                    // Loop through properties
                    Parallel.ForEach(entity.GetType().GetProperties(),
                        property =>
                        {
                            // If accessible and has no parameters
                            if (property.CanRead && !(property.GetIndexParameters().Length > 0))
                            {
                                // Match properties by name
                                PropertyInfo other = typeof(T).GetProperty(property.Name);
                                if ((other != null) && (other.CanWrite))
                                    other.SetValue(newEntity, property.GetValue(entity, null), null);
                            }
                        });
                }
     
                return newEntity;
            }
     
        }
    Si tu peux parcourir en boucle ton dataset, il suffira de faire quelque chose comme ceci:

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
     
     
            public virtual IMyClass GetData()
            {
                var liste = new List<MaClasse>();
                Parallel.ForEach(DB.GetMyData(sql), result => { liste.Add(result.ConvertTo<MaClasse>()); } );
                return liste;
            }
    Il suffirait de mofidier ce code pour travailler avec des noms de colonnes plutôt que des propriétés.

    Sinon, tu peux aussi regarder le code source d'un ORM open source tel que celui-ci.

    http://code.google.com/p/servicestack/source/checkout

  5. #5
    Membre habitué
    Inscrit en
    mars 2007
    Messages
    114
    Détails du profil
    Informations forums :
    Inscription : mars 2007
    Messages : 114
    Points : 101
    Points
    101

    Par défaut

    Merci pour le tuyau.

    Je vais aussi investiguer du côté de LINQ to SQL pour essayer de régler mon problème sans code ou presque

  6. #6
    Membre habitué
    Inscrit en
    mars 2007
    Messages
    114
    Détails du profil
    Informations forums :
    Inscription : mars 2007
    Messages : 114
    Points : 101
    Points
    101

    Par défaut

    bon j'suis trop bête.

    mon code fonctionne parfaitement à condition d'allouer les listes dans le constructeur de Calendar ...

+ Répondre à la discussion
Cette discussion est résolue.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •