IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

datagrid et couche métier WPF


Sujet :

C#

  1. #1
    Membre habitué Avatar de snay13
    Homme Profil pro
    Inscrit en
    Juin 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2009
    Messages : 236
    Points : 166
    Points
    166
    Par défaut datagrid et couche métier WPF
    Bonjour,

    je sollicite vos conseils afin d'accélérer le chargement de ma datagrid tout en gardant la facilté de binding sur ma datagrid.

    Actuellement, pour charger 10 000 enregistrements dans ma datagrid, cela me prend environ 8 secondes

    Voici mon code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    <DataGrid x:Name="dgdEnregistrement" Margin="8,150,8,8" VerticalAlignment="Top" Style="{DynamicResource MyDataGridStyle}" 
                      ColumnHeaderStyle="{DynamicResource MyDataGridColumnHeaderStyle}" RowStyle="{DynamicResource MyDataGridRowStyle}" 
                      CellStyle="{DynamicResource MyDataGridCellStyle}">
     
    			<DataGrid.Columns>
                    <DataGridTextColumn Header="Code Id" Binding="{Binding id_util}"/>
                    <DataGridTextColumn Header="Nom" Binding="{Binding nom_util}">
                        <DataGridTextColumn.ElementStyle>
                            <Style TargetType="TextBlock">
                                <Setter Property="TextWrapping" Value="Wrap" />
                                <Setter Property="MaxWidth" Value="150" />
                            </Style>
                        </DataGridTextColumn.ElementStyle>
                    </DataGridTextColumn>
    				<DataGridTextColumn Header="Prénom" Binding="{Binding prn_util}">
                        <DataGridTextColumn.ElementStyle>
                            <Style TargetType="TextBlock">
                                <Setter Property="TextWrapping" Value="Wrap" />
                                <Setter Property="MaxWidth" Value="150" />
                            </Style>
                        </DataGridTextColumn.ElementStyle>
                    </DataGridTextColumn>
                    <DataGridTextColumn Header="Email" Binding="{Binding mail_util}">
                        <DataGridTextColumn.ElementStyle>
                            <Style TargetType="TextBlock">
                                <Setter Property="TextWrapping" Value="Wrap" />
                                <Setter Property="MaxWidth" Value="150" />
                            </Style>
                        </DataGridTextColumn.ElementStyle>
                    </DataGridTextColumn>
    				<DataGridTextColumn Header="Identifiant" Binding="{Binding nom_conn_util}">
                        <DataGridTextColumn.ElementStyle>
                            <Style TargetType="TextBlock">
                                <Setter Property="TextWrapping" Value="Wrap" />
                                <Setter Property="MaxWidth" Value="150" />
                            </Style>
                        </DataGridTextColumn.ElementStyle>
                    </DataGridTextColumn>
    				<DataGridTextColumn Header="Groupe" Binding="{Binding groupe.lib_grp}">
                        <DataGridTextColumn.ElementStyle>
                            <Style TargetType="TextBlock">
                                <Setter Property="TextWrapping" Value="Wrap" />
                                <Setter Property="MaxWidth" Value="150" />
                            </Style>
                        </DataGridTextColumn.ElementStyle>
                    </DataGridTextColumn>
    				<DataGridTextColumn Header="Configuration" Binding="{Binding groupe.acces_param}"/>
    				<DataGridTextColumn Header="Mise à jour" Binding="{Binding groupe.acces_maj}"/>
                    <DataGridTextColumn Header="Manuel" Binding="{Binding groupe.acces_manuel}"/>
                    <DataGridTextColumn Header="Prodotec" Binding="{Binding groupe.acces_gestProd}"/>
                    <DataGridTextColumn Header="Impression" Binding="{Binding groupe.acces_gestImp}"/>
    			</DataGrid.Columns>
     
    		</DataGrid>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    private void tbxRecherche_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
            {
                //Touche ENTER
                if (e == null || e.Key == Key.Enter)
                {
                    if (a == null)
                    {
                        a = new Thread(new ParameterizedThreadStart(LoadData));
                        a.Start(tbxRecherche.Text);
     
                    }
                }
            }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
     public void LoadData(Object param)
            {
                Application app = System.Windows.Application.Current;
                if (app != null)
                    app.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)delegate
                    {
                        x = new MyMessageBoxWait("Mise à jour des enregistrements");
                        x.ShowDialog();
                    });
     
     
                listUtilisateur = daoUtilisateur.FindAll(param.ToString());
     
     
     
                if (app != null)
                    app.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)delegate
                    {
                        if (listUtilisateur != null)
                        {
                            if (listUtilisateur != null && listUtilisateur.Count > 1)
                                lblEnregistrement.Content = listUtilisateur.Count + " Enregistrements";
                            else
                                lblEnregistrement.Content = listUtilisateur.Count + " Enregistrement";
                        }
                        else
                            lblEnregistrement.Content = "0 Enregistrement";
     
                        dgdEnregistrement.ItemsSource = listUtilisateur;
                        dgdEnregistrement.SelectedValue = listUtilisateur;
                        x.Visibility = Visibility.Hidden;
                        x.Close();
                    });
                a = null;
     
            }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
     public ObservableCollection<MdlUtilisateur> FindAll(String name = "")
            {
                //Requete
                string query = "SELECT id_util, nom_util, prn_util, mail_util, nom_conn_util, mdp_conn_util, id_grp "
                    + "FROM ls_util WHERE nom_util LIKE CONCAT('%', @param1, '%') AND vis_util = 1 ORDER BY nom_util";
     
                MySqlCommand cmd = null;
                MySqlDataAdapter ad = null;
                DataTable dt = null;
                DaoGroupe daoGroupe = null;
                ObservableCollection<MdlUtilisateur> listUtilisateur;
                try
                {
                    //Preparation de la requete
                    cmd = new MySqlCommand(query, this.connection);
                    cmd.Parameters.AddWithValue("@param1", name);
                    ad = new MySqlDataAdapter();
                    ad.SelectCommand = cmd;
                    dt = new DataTable();
                    ad.Fill(dt);
     
                    //Resultat
                    if (dt.Rows.Count != 0)
                    {   
                        daoGroupe = FactoryDao.getDaoGroupe();
                        listUtilisateur = new ObservableCollection<MdlUtilisateur>();
                        foreach (DataRow dr in dt.Rows)
                        {
                            listUtilisateur.Add(new MdlUtilisateur(Convert.ToInt64(dr[0]), dr[1].ToString(), dr[2].ToString(),
                                dr[3].ToString(), dr[4].ToString(), dr[5].ToString(), daoGroupe.findById(Convert.ToInt64(dr[6]))));
                        }
     
                        return listUtilisateur;
                    }
                    else
                        return null;
                }
                catch (Exception ex)
                {
                    UtilsUi.ShowMessageError(ex);
                    return null;
                }
                finally
                {
                    //Liberation des ressources
                    cmd.Dispose();
                    ad.Dispose();
                    dt.Dispose();
                    daoGroupe = null;
                    listUtilisateur = null;
                }
            }
    Ce qui me prends du temps, ce n'est pas l'éxécution de la requête en elle même mais la génération du modele métier dans la méthode FindAll

    Est ce la bonne méthode ?
    Comment puis je accélérer tout ça ?

    Merci

  2. #2
    Membre expert


    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2006
    Messages
    970
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 970
    Points : 3 304
    Points
    3 304
    Par défaut
    Bonjour,

    Pour ce que je vois dans votre code pour charger vos données dans un DataTable via la méthode Fill du MySqlDataAdapter.

    Ensuite vous repasser tous les enregistrements chargés pour les placer dans une ObservableCollection que vous liez à votre Datagrid.

    Pourquoi ne pas lier directement votre DataGrid au DataTable et donc éviter le remplissage de la collection ?

  3. #3
    Membre habitué Avatar de snay13
    Homme Profil pro
    Inscrit en
    Juin 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2009
    Messages : 236
    Points : 166
    Points
    166
    Par défaut
    Bonjour,

    Je passe par une collection afin d'utiliser la facilité de binding pour mes objets

    Par exemple :

    - Pour les DataGridTextColumn dans mon code xaml ci dessus

    - Pour les liens avec les clés étrangères
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    public class MdlUtilisateur
        {
            /*Constructeurs*/
            public MdlUtilisateur() {}
     
            public MdlUtilisateur(String nom_util, String prn_util, String mail_util, String nom_conn_util,
                String mdp_conn_util, ModeleGroupe groupe) 
            {
                this.nom_util = nom_util;
                this.prn_util = prn_util;
                this.mail_util = mail_util;
                this.nom_conn_util = nom_conn_util;
                this.mdp_conn_util = mdp_conn_util;
                this.groupe = groupe;
            }
     
            public MdlUtilisateur(long id_util, String nom_util, String prn_util, String mail_util, String nom_conn_util,
                String mdp_conn_util, ModeleGroupe id_grp) : this(nom_util, prn_util, mail_util, nom_conn_util, mdp_conn_util, id_grp)
            {
                    this.id_util = id_util;
            }
     
            /*Propriétés*/
            public long id_util { get; set; }
            public String nom_util { get; set; }
            public String prn_util { get; set; }
            public String mail_util { get; set; }
            public String nom_conn_util { get; set; }
            public String mdp_conn_util { get; set; }
            public ModeleGroupe groupe { get; set; }
        }
    - Pour récupérer la ligne sélectionné de ma DataGrid, je récupère directement l'objet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    utilisateur = (MdlUtilisateur)dgdEnregistrement.SelectedValue;
    Mais effectivement c'est ce transfert de ma DataTable vers ma Collection qui prends du temps

  4. #4
    Expert confirmé

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    2 066
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 2 066
    Points : 4 233
    Points
    4 233
    Par défaut
    Pourquoi utiliser une datatable, tu peux mettre tes objets directement dans une observableCollection lors de l'accès à ta BDD en utilisant un datareader.

  5. #5
    Membre habitué Avatar de snay13
    Homme Profil pro
    Inscrit en
    Juin 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2009
    Messages : 236
    Points : 166
    Points
    166
    Par défaut
    Effectivement, mais avec un DataReader, j'obtiens une erreur car pour chaque ligne, je lance une requête sur la clé étrangère afin de créer mon modèle pour le groupe.

    Du coup, j'ai revu mon architecture et j'utilise une jointure dans ma requête et les performances sont nettement meilleures et même acceptable (environ 1s)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    public ObservableCollection<MdlUtilisateur> FindAll(String name = "")
            {
                //Requete
                string query = "SELECT id_util, nom_util, prn_util, mail_util, nom_conn_util, mdp_conn_util, lib_grp, note_grp, acces_param, acces_maj, acces_manuel, acces_gestProd, acces_gestImp "
                    + "FROM ls_util, ls_grp WHERE nom_util LIKE CONCAT('%', @param1, '%') AND vis_util = 1 AND ls_util.id_grp = ls_grp.id_grp ORDER BY nom_util";
     
                MySqlCommand cmd = null;
                MySqlDataReader dr = null;
                DaoGroupe daoGroupe = FactoryDao.getDaoGroupe();;
                ObservableCollection<MdlUtilisateur> listUtilisateur;
                try
                {
                    //Preparation de la requete
                    cmd = new MySqlCommand(query, this.connection);
                    cmd.Parameters.AddWithValue("@param1", name);
     
                    dr = cmd.ExecuteReader();
     
                    if(dr.HasRows) {
                        listUtilisateur = new ObservableCollection<MdlUtilisateur>();
                        while (dr.Read())
                        {
                            listUtilisateur.Add(new MdlUtilisateur(dr.GetInt64(0), dr.GetString(1), dr.GetString(2), dr.GetString(3), dr.GetString(4),
                                dr.GetString(5), new ModeleGroupe(dr.GetString(6), dr.GetString(7), dr.GetInt32(8), dr.GetInt32(9), dr.GetInt32(10), dr.GetInt32(11), dr.GetInt32(12))));
                        }
                        return listUtilisateur;
                    }
                    else
                        return null;
                }
                catch (Exception ex)
                {
                    UtilsUi.ShowMessageError(ex);
                    return null;
                }
                finally
                {
                    //Liberation des ressources
                    cmd.Dispose();
                    dr.Close();
                    daoGroupe = null;
                    listUtilisateur = null;
                }
            }
    Est ce la bonne solution ?
    Existe il une meilleure solution ?

  6. #6
    Expert confirmé

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    2 066
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 2 066
    Points : 4 233
    Points
    4 233
    Par défaut
    Justement c'est une jointure qu'il faut faire et non deux requête séparé, tu as quand même bien amélioré les performances.

    Après ton code n'est pas le plus claire non plus mais c'est ça dans l'idée qu'il faut faire (le getstring directement dans le add c'est pas le plus propre non plus et le faire par numéro de colonne ca peux poser des pb).
    Pour ton nom s'il est vide pourquoi utilisé un Like dans ce cas, je pense que ça te fait perdre du temps autant faire deux méthodes (une avec le like une sans).

Discussions similaires

  1. Architecture couche métier <-> couche présentation
    Par bozo614 dans le forum Visual C++
    Réponses: 7
    Dernier message: 22/11/2007, 17h11
  2. [EJB] Architecture couche métier + packaging
    Par st0ne dans le forum Java EE
    Réponses: 2
    Dernier message: 26/10/2007, 10h57
  3. Relation entre EJB, couche métiers, JSP et servlet
    Par infinity21 dans le forum Servlets/JSP
    Réponses: 13
    Dernier message: 05/03/2007, 23h50
  4. Organisation Couche métier
    Par tatemilio2 dans le forum Hibernate
    Réponses: 1
    Dernier message: 08/09/2006, 14h29
  5. Couche métier = forcement EJB ?
    Par jothi35 dans le forum Java EE
    Réponses: 9
    Dernier message: 14/09/2004, 16h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo