Partage
  • Partager sur Facebook
  • Partager sur Twitter

Liaison Model et ViewModel

c#

Sujet résolu
    29 novembre 2018 à 18:21:32

    Pourquoi ne pas planquer toute cette complexité de la base à EF, en utilisant des vues en base de données, par exemple.
    • Partager sur Facebook
    • Partager sur Twitter
    Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
      29 novembre 2018 à 18:35:56

      Merci bacelar pour ta réponse mais j'avoue ne rien comprendre... Pourrais-tu détailler un peu plus, je suis très loin d'être un crack en EF et C#.

      Merci

      • Partager sur Facebook
      • Partager sur Twitter
        29 novembre 2018 à 18:43:27

        C'est pas vraiment ni de l'EF ni du C#.

        C'est de la base de données.

        Si EF fonctionne sur l'ensemble des mois de l'année mais que les données sont sur plusieurs tables en base, si vous créez une vue qui regroupe l'ensemble des tables via une vue ( avec des UNION SQL), EF ne verra pas la différence avec une seule table.

        Si vous avez besoin de faire un filtrage par mois, vous n'avez qu'à ajouter des conditions au niveau de EF.

        Le sens principal de mon intervention, c'est de cacher la complexité de la base de données à EF en utilisant tous les outils de base de données pour "virtualiser" la base de données, comme les vues.

        • Partager sur Facebook
        • Partager sur Twitter
        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
          29 novembre 2018 à 19:22:20

          Merci de continuer à me donner des solutions c'est vraiment sympa. Le seul problème est que je suis débutant et que tout ce que tu me racontes reste incompréhensible pour mon modeste niveau.

          Pourrais-tu si tu le veux bien me donner un exemple ou me proposer une piste plus simple pour moi.

          Merci

          • Partager sur Facebook
          • Partager sur Twitter
            29 novembre 2018 à 19:37:25

            Peux-tu faire une copie d'écran avec l'ensemble des tables de ta base et le gestionnaire de base de données que tu utilises. (Oracle, SQL Server, MySQL etc..)
            • Partager sur Facebook
            • Partager sur Twitter
            Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
              29 novembre 2018 à 23:07:57

              Je te donne une table de la base car elles sont toutes identiques

              namespace GestionComptes.DAL
              {
                  [Table("Janvier")]
                  public class Janvier
                  {
                      [Key]
                      public int JanvierId { get; set; }
              
                      public char Type { get; set; }
                      public bool Changement { get; set; }
                      public bool Validation { get; set; }
                      public string DateCB { get; set; }
                      public string NumeroCheque { get; set; }
                      public string Operation { get; set; }
                      public decimal Debit { get; set; }
                      public decimal Credit { get; set; }
                  }
              }
              

              et le gestionnaire de la base:

              namespace Compte_Bancaire.Models

              {

                  public class BddContext:DbContext

                  {

                      public BddContext(string NomBase) : base(@"Data Source=(localdb)\v11.0; AttachDbFileName=D:\\Compte Bancaire\\Compte Bancaire\\Bases\\" + NomBase + ";Integrated Security=true;")

                      {

                          Database.SetInitializer<BddContext>(new DropCreateDatabaseIfModelChanges<BddContext>());

                      }

                      public DbSet<Janvier> Janviers { get; set; }

                      public DbSet<Fevrier> Fevriers { get; set; }

                      public DbSet<Mars> Mars { get; set; }

                      public DbSet<Avril> Avrils { get; set; }

                      public DbSet<Mai> Mais { get; set; }

                      public DbSet<Juin> Juins { get; set; }

                      public DbSet<Juillet> Juillets { get; set; }

                      public DbSet<Aout> Aouts { get; set; }

                      public DbSet<Septembre> Septembres { get; set; }

                      public DbSet<Octobre> Octobres { get; set; }

                      public DbSet<Novembre> Novembres { get; set; }

                      public DbSet<Decembre> Decembres { get; set; }

                  }

              }

              Voilà je pense t'avoir donné ce que tu m'as demandé.
              Merci de jeter un coup d’œil...



              • Partager sur Facebook
              • Partager sur Twitter
                30 novembre 2018 à 14:04:26

                Heu....Et ça sert à quoi d'avoir plusieurs mois de Novembre, plusieurs mois de Janvier, etc...? o_O o_O

                A mon avis, le problème est que tu veux faire "trop complexe" pour quelque chose qui est surement très simple; Ou, dit autrement, tu cherches (encore) midi à quatorze heure.

                Jamais un logiciel n'indexerait des opérations financière de la sorte.

                Une opération financière, c'est quoi? C'est un montant...Une date d'opération (pourquoi pas découper ça en 2 : date d'ordre et date d'exécution), et d'autres données plus ou moins utile : Un nom (pour être user-friendly), des informations relative au système utilisé pour réaliser l'opération (N° de chèque, etc.).

                Où est-ce que tu vois, dans ce descriptif, que ces entrées d'opération sont (physiquement) rangées par mois d'exécution??? Non, une opération financière, ça se décrit de la sorte, et c'est tout, rien de plus. Il n'y a qu'une seule table (physique) pour stocker ça, où chaque ligne représentera 1 opération financière.

                Ce que "des logiciels" feront de ces données, la base de données n'en a cure! (Sauf exception assez spécifique, des ERP, où l'interface utilisateur est souvent intimement liée à ce qui se trouve en base de données...Du coup, oui, dans ce cas là, comme le précise bacelar, on aura tendance à créer la fameuse table des opérations, sans aucun accès pour les users, et des vues SQL, parfois partagées, parfois spécifique à un compte utilisateur donné. A noter que les vues SQL ne sont pas des tables de stockage "physique", mais des "représentations logique de données" issues d'autres vues ou tables "physique"). Dans ton cas, c'est ton logiciel qui offre la faculté de filtrer ou regrouper suivant certains critères. Pour ça, tu auras plusieurs solutions :

                • Soit tu fais tout ça toi même, logiciellement :
                IEnumerable<Operation> opes = tonContext.Operations;
                List<Operation> filtered = new List<Operation>();
                foreach(Operation o in opes)
                {
                   if(o.Type == "UnTypeDoperation")
                   {
                       filtered.Add(o);
                   }
                }
                
                //Et là, le résultat attendu se trouve dans la liste filtered.
                • Soit tu utilises les fonctionnalités du moteur de données. Avec Linq-To-Entities & EF, c'est aussi simple que d'écrire :
                List<Operation> filtered = (from o in tonContext.Operations
                                            where o.Type == "UnTypeDoperation"
                                            select o).ToList();

                Le choix entre les 2 sera déterminé par la volumétrie de données. Si le premier cas peut être utile pour filtrer/trier/regrouper moins d'un millier d'entrée, il est inutilisable quand il s'agit de brasser des millions d'entrée.

                Autre chose :

                berduf a écrit:

                Je te donne une table de la base car elles sont toutes identiques


                Alors, poses toi les bonnes question. L'informatique est là pour simplifier/accélérer les choses...Si tu fais quelque chose de compliqué, tu fonce très certainement droit dans un mur et il te faut penser la chose autrement. Dupliquer 12 fois la même structure de données, c'est une forme de complexité.

                Edit : Je n'ai pris l'exemple que des filtrages de données...Mais naturellement, c'est valable pour beaucoup de manipulation, comme le regroupement ou l'aggrégation.

                A noter également que WPF propose aussi plein de solution pour adresser les même problématique de filtrage, regroupement, tri, ... Quand tu clique sur l'entête d'une colonne d'une DataGrid, ça utilise le système de tri des CollectionView pour ordonner les données de la grille dans une "liste proxy" (les CollectionView) remplie à partir de ta liste réelle.

                -
                Edité par Nisnor 30 novembre 2018 à 14:13:19

                • Partager sur Facebook
                • Partager sur Twitter
                  30 novembre 2018 à 14:55:15

                  Merci Nisnor de me remettre les pieds sur terre. Tu as raison je crois que j'ai mal réfléchi à la structure de ma base de données. Je vais remédier à cela et je pense avoir beaucoup moins de problèmes.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    6 décembre 2018 à 10:02:25

                    Bonjour Nisnor,

                    A la suite de tes conseils j'ai remanié mon projet en n'utilisant plus que trois tables dans une base de données par année. Tout fonctionne bien sauf le rafraîchissement de l'affichage. Je t'explique:

                    J'ai une MainWindow qui affiche un UserControl pour les entrées. Dans la MainWindow je peux choisir le mois que je désire afficher. Tout va bien lors de la mise en route de l'appli. J'affiche dans une DataGrid le mois courant sans souci. Mais quand je change de mois l'affichage dans le DataGrid ne change pas alors que les affichages des différents calculs ont l'air de fonctionner correctement.

                    Je te transmet les morceaux de code concernés:

                    La vue:

                    <DataGridTextColumn  Foreground="{DynamicResource TxtEntree}" FontFamily="Comic Sans MS" Header="Opérations" Width="202" 
                                                             Binding="{Binding OperationEntree, Mode=TwoWay}" FontWeight="Bold" CanUserReorder="False" FontSize="11"/>
                    
                                        <DataGridTextColumn  Foreground="{DynamicResource TxtEntree}" FontFamily="Comic Sans MS" Header="Crédit" Width="100" 
                                                             Binding="{Binding CreditEntree, Mode=TwoWay, StringFormat={}{0:N2},ConverterCulture=fr}" FontWeight="Bold" FontSize="11"/>
                                    </DataGrid.Columns>
                    

                    Pour le ViewModel du UserControl:

                     public class UcEntreeViewModel : Notifiable
                        {
                            #region Constructeur
                            public UcEntreeViewModel()
                            {
                                ItemEntree = new ObservableCollection<CollectionEntree>(ServiceOperationMensuelle.GetOperationEntree());
                                OnNewCollectionEntreeAdded(this.ItemEntree);
                                ItemEntree.CollectionChanged += ItemEntree_CollectionChanged;
                                ItemEntree.Sum(e => e.CreditEntree);
                                RaisePropertyChanged(nameof(UcEntreeViewModel.TotalEntree));
                                Mediator.MediatorCalcul.CalculEntree = TotalEntree;
                            }
                            
                            #endregion
                    
                            #region Propriétés
                            public int Cle;
                            
                    
                            private ObservableCollection<CollectionEntree> itemEntree;
                            public ObservableCollection<CollectionEntree> ItemEntree
                            {
                                set
                                {
                                    itemEntree = value;
                                    RaisePropertyChanged(nameof(UcEntreeViewModel.ItemEntree));
                                }
                                get
                                {
                                    return itemEntree;
                                }
                            }
                    
                            private CollectionEntree itemSelectionne;
                            public CollectionEntree ItemSelectionne
                            {
                                set
                                {
                                    if (value != null)
                                    {
                                        itemSelectionne = value;
                                        Cle = itemSelectionne.CleEntree;
                                    }
                                    RaisePropertyChanged(nameof(UcEntreeViewModel.ItemSelectionne));
                                }
                                get
                                {
                                    return itemSelectionne;
                                }
                            }
                    
                            public decimal TotalEntree
                            {
                                get
                                {
                                    return this.ItemEntree.Sum(e => e.CreditEntree);
                                }
                            }
                            #endregion
                    
                            private void OnNewCollectionEntreeAdded(IEnumerable<CollectionEntree> entries)
                            {
                                if (entries != null)
                                {
                                    foreach (CollectionEntree e in entries)
                                    {
                                        e.PropertyChanged += this.Entree_PropertyChanged;
                                    }
                                }
                            }
                    
                            private void ItemEntree_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
                            {
                                // Détection de l'ajout ou du changement d'un item dans la collection
                                if (e.NewItems != null)
                                {
                                    foreach (CollectionEntree entree in e.NewItems)
                                    {
                                        entree.PropertyChanged += Entree_PropertyChanged;
                                    }
                                }
                                // Détection de la suppression d'un item dans la collection
                                if (e.OldItems!=null)
                                {
                                    foreach (CollectionEntree entree in e.OldItems)
                                    {
                                        entree.PropertyChanged -= Entree_PropertyChanged;
                                        OnNewCollectionEntreeAdded(e.NewItems?.Cast<CollectionEntree>());
                                        Mediator.MediatorCalcul.CalculEntree = TotalEntree;
                    
                                        var ControlEntree = Mediator.Bdd.Entrees.Find(Cle);
                                        Mediator.Bdd.Entrees.Remove(ControlEntree);
                                    }
                                }
                            }
                    
                            // Mise à jour de l'observablecollection
                            private void Entree_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
                            {
                                    var entree = new CollectionEntree()
                                    {
                                        ValidEntree=ItemSelectionne.ValidEntree,
                                        OperationEntree = ItemSelectionne.OperationEntree,
                                        CreditEntree = ItemSelectionne.CreditEntree
                                    };
                    
                                RaisePropertyChanged(nameof(UcEntreeViewModel.TotalEntree));
                                Mediator.MediatorCalcul.CalculEntree = TotalEntree;
                    
                                // Enregistrement dans la base d'une nouvelle opération
                                if (Cle== 0 && ItemSelectionne.OperationEntree != null && ItemSelectionne.CreditEntree != 0)
                                    {
                                        var ControlEntree = new Entree();
                                        {
                                            ControlEntree.Mois = Mediator.MediatorUtile.NomMois;
                                            ControlEntree.Changement = false;
                                            ControlEntree.Validation = ItemSelectionne.ValidEntree;
                                            ControlEntree.Operation = ItemSelectionne.OperationEntree;
                                            ControlEntree.Credit = ItemSelectionne.CreditEntree;
                                        }
                                    Mediator.Bdd.Entrees.Add(ControlEntree);
                                    }
                    
                                    // Enregistrement dans la base de la modification d'une opération
                                    if (Cle!=0 && ItemSelectionne.OperationEntree != null && ItemSelectionne.CreditEntree != 0)
                                    {
                                    var ControlEntree = Mediator.Bdd.Entrees.Find(Cle);
                                        {
                                            ControlEntree.Mois = Mediator.MediatorUtile.NomMois;
                                            ControlEntree.Changement = true;
                                            ControlEntree.Validation = ItemSelectionne.ValidEntree;
                                            ControlEntree.Operation = ItemSelectionne.OperationEntree;
                                            ControlEntree.Credit = ItemSelectionne.CreditEntree;
                                        }
                                    }
                            }
                        }
                    }

                    Pour le ViewModel de la MainWindow j'ai écrit cette ligne mais je ne suis pas certain que ce soit très "propre"!!!

                    private void MediatorUtile_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
                            {
                                UcEntreeViewModel Uc = new UcEntreeViewModel();
                            }

                    Et enfin pour la classe ServiceOperationMensuelle:

                    public static IEnumerable<CollectionEntree> GetOperationEntree()
                            {
                                    return from c in Mediator.Bdd.Entrees where c.Mois==Mediator.MediatorUtile.NomMois
                                           select new CollectionEntree
                                           {
                                               CleEntree = c.EntreeId,
                                               ValidEntree = c.Validation,
                                               OperationEntree = c.Operation,
                                               CreditEntree = c.Credit
                                           };
                            }

                    Peux-tu, s'il te plait, me donner encore une piste pour résoudre ce petit problème.

                    Merci par avance.




                    • Partager sur Facebook
                    • Partager sur Twitter
                      7 décembre 2018 à 15:19:31

                      Je ne comprends pas comment, ce que tu cherche à faire, peut fonctionner :

                      • Dans le code métier posté ici, aucune action n'est réalisée, visant à mettre à jour la source de données lorsque le mois sélectionné change.
                      • Le code XAML indiqué est très largement insuffisant. De même que la première remarque : Aucun élément UI ne permet, de toute façon, de modifier quoique ce soit de relatif au mois d'affichage.
                      • Oui, ça fonctionne au 1er lancement, parce que la valeur par défaut est sans doute renseignée en dur dans le code et que c'est le seul cas qui est couvert ici (appliquer un filtre au mois, qui ne change pas)
                      • Partager sur Facebook
                      • Partager sur Twitter
                        7 décembre 2018 à 15:42:38

                        Merci Nisnor pour ta réponse même si j'ai un peu l'impression de t'énerver.

                        Voici les codes qui pourront te donner l'idée de ce que j'ai fait:

                        La partie du Xaml pour l'expander qui s'occupe des mois:

                        <Expander x:Name="ExpandMois" Header="MOIS" Style="{Binding Mode=OneWay, Source={StaticResource ExpanderMenu}}"  Foreground="{DynamicResource TextColor}" Margin="10,0,5,5" FontSize="11" FontStyle="Italic" Cursor="Hand" IsExpanded="{Binding ExpandMois}" Width="100" HorizontalAlignment="Center" FontWeight="Bold" >
                                                    <StackPanel >
                                                        <ListBox x:Name="ListMois" FontWeight="Normal" Foreground="{DynamicResource TextColor}" Background="{x:Null}" BorderBrush="{x:Null}" Margin="0,0,5,0" Padding="0"  Cursor="Hand" ItemsSource="{Binding Mois}" DisplayMemberPath="Nom" SelectedIndex="{Binding IndexMoisSelectionne, Mode=TwoWay}"/>
                                                    </StackPanel>
                                                </Expander>

                        et le code métier:

                        private int indexMoisSelectionne;
                                public int IndexMoisSelectionne
                                {
                                    set
                                    {
                                        indexMoisSelectionne = value;
                                        RaisePropertyChanged(nameof(MainViewModel.IndexMoisSelectionne));
                                        MoisSelectionneMethode();
                                    }
                                    get
                                    {
                                        return indexMoisSelectionne;
                                    }
                                }private void MoisSelectionneMethode()
                                {
                                    // Fermeture des expander
                                    ExpandMois = false; 
                                    ExpandAnnee = false;
                        
                                    // Mise en place du mois et de l'année
                                    NomMois = Mois[IndexMoisSelectionne].Nom;
                                    NomAnnee = Annee[IndexAnneeSelectionne ].NomAnnee;
                        
                         // Mise à jour de MediatorUtile
                                    Mediator.MediatorUtile.NomMois = NomMois;
                                    Mediator.MediatorUtile.NumeroAnnee = NomAnnee;
                                    Mediator.MediatorUtile.PropertyChanged += MediatorUtile_PropertyChanged;
                        
                        }
                        
                                private void MediatorUtile_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
                                {
                                    UcEntreeViewModel Uc = new UcEntreeViewModel();
                                }


                        Tous les changements qui doivent avoir lieu sur la vue s'effectuent sauf la mise à jour de la datagrid.

                        Merci de te prendre encore un peu de temps.

                        -
                        Edité par berduf 7 décembre 2018 à 19:34:44

                        • Partager sur Facebook
                        • Partager sur Twitter
                          10 décembre 2018 à 12:07:51

                          "même si j'ai un peu l'impression de t'énerver."

                          Ce qui me chagrine dans l'affaire, c'est surtout que j'ai l'impression que veux directement gravir l'Everest, sans vouloir t'entrainer d'abord sur des murs d'escalade et que, quoiqu'en dise les personnes à qui tu poses tes questions, tu t'obstine à vouloir commencer par l'Everest.

                          Par exemple, dans ton code C# là, concentrons nous 5 minutes sur 1 seule ligne : la N°33. C'est peut-être un artefact laissé là par inadvertance, mais si il est là, c'est que tu as au moins essayé quelque chose. Sauf que, ce "quelque chose" ne semble avoir ni queue, ni tête. Est-ce que tu as compris ce que "new" faisait? Je veux dire : Vraiment compris. Parce que si tu me répond "Bin ça permet que Visual Studio m'affiche la liste des trucs que je peux faire", alors non, tu n'as pas compris ce que ça faisait ce "new".

                          Un peu avant dans ce projet, je t'ai sorti une solution de facilité à un problème : Utiliser un static, avec un bout de code à l'appui. Cool, copie-colle, adapte un peu les endroits & les noms et "ça marche". Mais as-tu compris ce que ce "static" implique?

                          Trop souvent, depuis le début de ce projet, tu rencontres des problèmes qui sont purement liés à une méconnaissance du fonctionnement Objet. Pas parce que tu ne le comprends pas...Mais parce que tu as voulu gravir l'Everest sans commencer par des murs d'escalade en salle.

                          Quand "on" conseille de démarrer par un projet console, c'est pas juste pour faire chier. Une IHM, ça rajoute des complexités technique plus ou moins importantes. Si tu enlèves ces complexités, ça te permet justement de te focaliser sur l'assimilation des rudiments Objet de .NET. Sans ça, sans ces rudiments, oui, ce sera trèèèèèèèès compliqué d'avancer vite (parce que tu te prends les problématiques liées à l'absence de maitrise des rudiments + les problématiques liées à la techno IHM choisie, en même temps).

                          Une fois que tu maitrise ces rudiments, rajouter une IHM par dessus, c'est "Cadeau". Oui, il y aura forcément des particularités techniques propre à l'IHM, mais si tu n'es plus freiné par les rudiments objets, y'en aura même certaines (de particularités technique [qui posent problème]) que tu sauras résoudre toi même, juste en essayant des trucs.

                          "Tous les changements qui doivent avoir lieu sur la vue s'effectuent sauf la mise à jour de la datagrid."

                          Dans ces nouveaux extraits de code, il n'y a toujours rien qui indique "Recharge la source de données de la DataGrid".

                          • Partager sur Facebook
                          • Partager sur Twitter
                            10 décembre 2018 à 13:08:50

                            Merci pour ta réponse Nisnor, mea culpa je pense d'avoir sollicité pour rien.

                            A mon age les choses rentrent plus doucement dans le cerveau :euh:. J'ai du mal a réfléchir et donc à réagir devant des dysfonctionnements. 

                            J'ai trouvé la solution. J'avais presque tout mais pas écrit au bon endroit. Je m’acharnais sur le MainViewModel mais il fallait que je travaille dans le UcEntreeViewModel.

                            J'avais laissé la ligne 33 par oubli. Je ne sais même pas pourquoi je l'avais écrite. Le désespoir de trouver la solution surement.

                            Par contre je ne sais peut être pas grand chose mais new je connais...

                            Je pense en fait que je n'ai pas confiance en moi et que je pense ne pas être capable de me sortir d'une difficulté qui d'ailleurs ne devrait pas en être une.

                            Encore merci et je vais essayé de me faire discret :)

                            -
                            Edité par berduf 11 décembre 2018 à 0:15:31

                            • Partager sur Facebook
                            • Partager sur Twitter

                            Liaison Model et ViewModel

                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                            • Editeur
                            • Markdown