none
ADO.Net Entity Data Model et héritage RRS feed

  • Question

  • Bonjour,

    Je souhaite mettre en place le EDM fourni par .NET 3.5 SP1 sur une base MySQL dont le modèle relationnel n'est pas définit.

    Pour cela, je souhaite définir mon modèle relationnel au niveau des objets, en héritant des classes que me fournit l'EDM et en ajoutant la couche relationnelle.

    Manque de chance ou de clairvoyance, cela ne fonctionne pas...

    Mon modèle est pour le moment simple : un entête de liste et des items associés, mon EDM me fournissant respectivement les classes BaseListe et BaseItem.

    Pour le moment, je ne me préoccupe que de mon entête, avec le code suivant :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Copilote.BDCopilote
    {
      public class Liste : BaseListe
      {
        #region Propriétés privées
        #endregion
    
        #region Propriétés publiques
        public Boolean IsNew;
        #endregion
    
        #region Constructeurs
        public Liste(string libelle, string mode, bool allowNew)
        {
          // On regarde dans la base si la liste existe déjà
          IQueryable<BaseListe> recherche = from liste in BDCopilote.Instance.BaseListeJeu
                           where liste.Libelle == libelle && liste.Mode == mode
                           select liste;
          this.IsNew = (recherche.Count() == 0);
          if (!this.IsNew)
          {
            // La liste existe déjà, on la charge dans l'objet courant
            BaseListe Element = recherche.First();
            this.Destinataire = Element.Destinataire;
            this.Dotation = Element.Dotation;
            this.DTCreate = Element.DTCreate;
            this.DTModif = Element.DTModif;
            this.EntityKey = Element.EntityKey;
            this.Etat = Element.Etat;
            this.Fusion = Element.Fusion;
            this.Libelle = Element.Libelle;
            this.Mode = Element.Mode;
            this.NbItem = Element.NbItem;
            this.x_date_rece = Element.x_date_rece;
            this.x_imp_transfert = Element.x_imp_transfert;
            this.x_interface = Element.x_interface;
            this.x_num_ipp = Element.x_num_ipp;
            this.x_num_sej = Element.x_num_sej;
            this.x_pk = Element.x_pk;
            this.x_sequence = Element.x_sequence;
            this.x_zone_deb = Element.x_zone_deb;
            this.x_zone_fin = Element.x_zone_fin;
          }
          else
          {
            if (allowNew)
            {
              // On initialise une nouvelle liste
              this.DTCreate = DateTime.Now;
              this.DTModif = DateTime.Now;
              this.Etat = "V";
              this.Libelle = libelle;
              this.Mode = mode;
              this.NbItem = 0;
            }
          }
        }
        #endregion
    
        #region Méthodes publiques
        public void SaveInDB()
        {
          BDCopilote.Instance.AddToBaseListeJeu(this);
        }
        #endregion
      }
    }
    
    

    La ligne "BDCopilote.Instance.AddToBaseListeJeu(this);" génère l’exception "InvalidOperationException" avec le message "Le mappage d'objet est introuvable pour le type ayant l'identité « Copilote.BDCopilote.Liste »."

    Et un cast de Liste vers BaseListe ne change rien...

    Any idea ??

    jeudi 5 mai 2011 15:30

Réponses

Toutes les réponses

  • Bonjour,

    Pouvez-vous nous montrer aussi le code pour la méthode BDCopilote.Instance.AddToBaseListeJeu ? Merci !

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    mardi 10 mai 2011 14:10
  • Bonjour,

    Il s'agit de la méthode construite par l'EDM :

        /// <summary>
        /// Il n'existe aucun commentaire pour BaseListeJeu dans le schéma.
        /// </summary>
        public void AddToBaseListeJeu(BaseListe baseListe)
        {
          base.AddObject("BaseListeJeu", baseListe);
        }
    
    
    Cordialement,

    mardi 10 mai 2011 14:16
  • Bonjour,

    Vu que vous avez une solution pour l’EDM sur ce thread est-ce que vous avez encore besoin d’une réponse pour cette question ?

     

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    mercredi 11 mai 2011 07:50
  • Bonjour,

    Il s'agit d'un problème distinct. Mon objectif maintenant est d'enrober la couche automatique générée par l'EDM avec mes problématiques métier...

    Dans le cadre de l'héritage, je n'arrive pas à transmettre les informations de mappage... J'ai trouvé une solution de contournement mais qui ne me satisfait pas dans la mesure ou je dois re-déclarer tous les champs extraits depuis l'EDM...

    Cordialement,

    mercredi 11 mai 2011 07:59
  • Bonjour,

    En ce cas, on a besoin de plus des informations sur la classe BDCopilote et sa propriété Instance aussi que sur le code ou la fonction SaveInDB() est appelée quand l’erreur est générée.

     

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    mercredi 11 mai 2011 08:10
  • pour la classe BDCopilote :

      /// <summary>Classe de gestion de la connexion à la BD</summary>
      public class BDCopilote : BaseCopiloteContainer, ILog
      {  
        #region Gestion par Design Pattern Singleton
        static readonly BDCopilote instance = new BDCopilote();
    
        // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
        static BDCopilote() { }
    
        /// <summary>Instance pour la gestion par Design Pattern Singleton</summary>
        public static BDCopilote Instance
        { get{ return instance; } }
        #endregion
    
        #region Constructeurs
        #endregion
    
        #region Méthodes publiques
        #endregion
    
        #region Implémentation de l'interface ILog
        /// <summary>
        /// Evénement permettant de logger
        /// </summary>
        public event LogEventHandler RaiseLogEvent;
    
        /// <summary>
        /// Méthode d'écriture de l'événement si l'événement est souscrit
        /// </summary>
        /// <param name="eventArg">Objet événement typé</param>
        public virtual void OnRaiseLogEvent(LogEventArgs eventArg)
        {
          // Make a temporary copy of the event to avoid possibility of
          // a race condition if the last subscriber unsubscribes
          // immediately after the null check and before the event is raised.
          LogEventHandler handler = RaiseLogEvent;
    
          // Event will be null if there are no subscribers
          if (handler != null)
          {
            // Use the () operator to raise the event.
            handler(this, eventArg);
          }
        }
        #endregion
      }
    
    

    pour la méthode SaveInDB() :

    public void SaveInDB()
    {
     BDCopilote.Instance.AddToBaseListeJeu(this);
    }
    

    pour l'appel, c'est simplement :

    Liste listeEnCours = new Liste(maListe, "S", true);
    listeEnCours.SaveInDB();
    
    
    Cordialement,

    mercredi 11 mai 2011 08:19
  • Bonjour,

    Une dernière question : la fonction AddToBaseListeJeu() est definie dans la classe BaseCopiloteContainer ? Si oui, j’aurais besoin de voir aussi cette classe parce que ce n’est pas clair pour moi d’où vient l’appel base.AddObject. Il sera utile de voir aussi le code ou la signature de cette dernière fonction. Merci !

     

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    mercredi 11 mai 2011 08:36
  • Oui, généré automatiquement à partir de l'EDM, et pour ce qui est de la fonction base.AddObject, je ne sais pas trop d'où elle vient...

    Par contre, je ne peux pas poster les 4600 lignes du fichier BaseCopilote.Designer.cs généré par l'EDM... Ca passe pas...

    mercredi 11 mai 2011 09:05
  • Bonjour,

    En cette situation je peux seulement deviner d’où vient l’erreur : la méthode construite devrait recevoir un objet du type BaseListeJeu si ce type a été défini et la signature de la fonction a été changée dans BaseCopilote.Designer.cs. Si tout ce code a été généré automatiquement et la classe BaseListeJeu n’existe pas, l’erreur vient de la manière dans lequel vous utilisez la classe Liste. Je crois qu’il ne faut pas définir un nouvelle classe qui hérite de BaseListe, mais il faut modifier directement la classe BaseListe, vu qu’il est une « partial class » et le mappage des objets BaseListe est défini.

     

    Cordialement,

    Cipri

     


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    mercredi 11 mai 2011 11:09
  • Je n'avais pas vu que la classe BaseListe était partiale, donc complétable... Mais cela ne me convient pas complètement... En effet mon objectif était d'enrichir l'expression de l'EDM de contraintes fonctionnelles et de relations or mes contraintes fonctionnelles devraient être implémentées au niveau des get et set des propriétés qui sont dans le Designer.cs...

    Du coup, j'ai contourné le problème de cette façon, peu élégante à mon goût :

      public class Liste
      {
        #region Propriétés privées
        /// <summary>Pointeur sur l'élément de base de données</summary>
        private BaseListe entete = null;
        /// <summary>Tableau des items associés à la liste. On ne le charge que si besoin.</summary>
        private List<Item> items = null;
        #endregion
    
        #region Propriétés publiques mappées sur l'entête
        // mappage de propriétés sur l'objet de BD interne
        /// <summary>Code destinataire de la liste.</summary>
        public string Destinataire
        {
          get { return this.entete.Destinataire; }
          set { this.entete.Destinataire = value; }
        }
        /// <summary>Code dotation associé à la liste.</summary>
        public string Dotation
        {
          get { return this.entete.Dotation; }
          set { this.entete.Dotation = value; }
        }
        /// <summary>Date heure de création de l'entête de liste. Propriété en lecture seule.</summary>
        public DateTime? DTCreate
        { get { return this.entete.DTCreate; } }
        /// <summary>Date heure de dernière modification de l'entête de liste. Propriété en lecture seule.</summary>
        public DateTime? DTModif
        { get { return this.entete.DTModif; } }
        /// <summary>Etat de la liste. Propriété en lecture seule. Valeurs possibles : V(ierge), E(ntamée), S(oldée).</summary>
        public string Etat
        { get { return this.entete.Etat; } }
        /// <summary>Nom de la fusion associée à la liste (sert pour le regroupement de liste).</summary>
        public string Fusion
        {
          get { return this.entete.Fusion; }
          set { this.entete.Fusion = value; }
        }
        /// <summary>Libellé de la liste. Propriété en lecture seule.</summary>
        public string Libelle
        { get { return this.entete.Libelle; } }
        /// <summary>Mode de la liste. Propriété en lecture seule. Valeurs possibles : E(ntrée), S(ortie), I(nventaire).</summary>
        public string Mode
        { get { return this.entete.Mode; } }
        /// <summary>Nombre de ligne dans la liste. Propriété en lecture seule.</summary>
        public int? NbItem
        { get { return this.entete.NbItem; } }
    
        /// <summary>???</summary>
        public DateTime? x_date_rece
        {
          get { return this.entete.x_date_rece; }
          set { this.entete.x_date_rece = value; }
        }
        /// <summary>???</summary>
        public Boolean? x_imp_transfert
        {
          get { return this.entete.x_imp_transfert; }
          set { this.entete.x_imp_transfert = value; }
        }
        /// <summary>???</summary>
        public string x_interface
        {
          get { return this.entete.x_interface; }
          set { this.entete.x_interface = value; }
        }
        /// <summary>???</summary>
        public string x_num_ipp
        {
          get { return this.entete.x_num_ipp; }
          set { this.entete.x_num_ipp = value; }
        }
        /// <summary>???</summary>
        public string x_num_sej
        {
          get { return this.entete.x_num_sej; }
          set { this.entete.x_num_sej = value; }
        }
        /// <summary>???</summary>
        public int x_pk
        { get { return this.entete.x_pk; } }
        /// <summary>???</summary>
        public string x_sequence
        {
          get { return this.entete.x_sequence; }
          set { this.entete.x_sequence = value; }
        }
        /// <summary>???</summary>
        public string x_zone_deb
        {
          get { return this.entete.x_zone_deb; }
          set { this.entete.x_zone_deb = value; }
        }
        /// <summary>???</summary>
        public string x_zone_fin
        {
          get { return this.entete.x_zone_fin; }
          set { this.entete.x_zone_fin = value; }
        }
        #endregion
    
        #region Propriétés publiques additionnelles
        /// <summary>Indicateur de nouvel enregistrement</summary>
        public Boolean IsNew { get; set; }
    
        /// <summary>Tableau des items associés à la liste. Propriété en lecture seule.</summary>
        public List<Item> Items
        {
          get
          {
            if (this.items == null)
            {
              // Les items n'ont pas été chargés, on va les chercher dans la base
              IQueryable<BaseItem> recherche = from items in BDCopilote.Instance.BaseItemJeu
                               where items.LibelleListe == this.Libelle && items.ModeListe == this.Mode
                               orderby items.NumeroItem ascending
                               select items;
              this.items = new List<Item>();
              if (recherche.Count() > 0)
              {
                foreach (BaseItem bitem in recherche)
                {
                  this.items.Add(new Item(bitem));
                }
              }
            }
            return this.items;
          }
        }
        #endregion
    
        #region Constructeurs
        /// <summary>
        /// Constructeur recherchant l'existance de la liste passée en paramètre
        /// </summary>
        /// <param name="libelle">Intitulé de la liste</param>
        /// <param name="mode">Mode de la liste (E,S,V)</param>
        /// <param name="allowNew">Autorise à créer une nouvelle liste si on ne la trouve pas</param>
        /// <exception cref="BDCreateException">Remontée si impossible de créer l'objet</exception>
        public Liste(string libelle, string mode, bool allowNew)
        {
          // On regarde dans la base si la liste existe déjà
          IQueryable<BaseListe> recherche = from liste in BDCopilote.Instance.BaseListeJeu
                           where liste.Libelle == libelle && liste.Mode == mode
                           select liste;
          this.IsNew = (recherche.Count() == 0);
          if (!this.IsNew)
          {
            // La liste existe déjà, on la charge dans l'objet courant
            this.entete = recherche.First();
          }
          else
          {
            if (allowNew)
            {
              // On initialise une nouvelle liste
              this.entete = new BaseListe();
              this.entete.DTCreate = DateTime.Now;
              this.entete.DTModif = DateTime.Now;
              this.entete.Etat = "V";
              this.entete.Libelle = libelle;
              this.entete.Mode = mode;
              this.entete.NbItem = 0;
              this.entete.x_interface = "";
              this.x_num_ipp = "";
              this.x_num_sej = "";
              this.x_sequence = "";
              this.x_zone_deb = "";
              this.x_zone_fin = "";
            }
            else
            {
              throw new BDCreateException("La liste n'existe pas et vous n'avez pas demandé à la créer.");
            }
          }
        }
        #endregion
    
        #region Méthodes publiques
        /// <summary>Méthode de sauvegarde en base de données</summary>
        /// <exception cref="BDSaveException">Remontée si problème lors de la sauvegarde en base</exception>
        public void SaveInDB()
        {
          if (this.entete != null)
          {
            // On démarre une transaction
            using (TransactionScope scope = new TransactionScope())
            {
              if (this.items.Count() > 0)
              {
                foreach (Item item in this.items)
                {
                  item.SaveInDB();
                }
              }
              if (this.IsNew)
              {
                BDCopilote.Instance.AddToBaseListeJeu(this.entete);
                BDCopilote.Instance.OnRaiseLogEvent(new LogEventArgs(TypeLog.Integrateur, TypeErreur.Information, "Ajout de la liste '" + this.Libelle + "' à la base."));
              }
              if (this.entete.EntityState == System.Data.EntityState.Modified)
              {
                this.entete.DTModif = DateTime.Now;
              }
              BDCopilote.Instance.SaveChanges();
              // Tout s'est bien passé, on commit le tout
              scope.Complete();
              //BDCopilote.Instance.AcceptAllChanges();
            }
          }
          else
          {
            throw new BDSaveException("Entête de liste non initialisé.");
          }
        }
    
        /// <summary>
        /// Ajout d'un item à la liste
        /// </summary>
        /// <param name="codeReference">Référence à ajouter</param>
        /// <param name="quantite">Quantité</param>
        public void AddItem(string codeReference, float quantite)
        {
          this.Items.Add(new Item(this.Libelle, this.Mode, this.GetNextIdItem(), true) {CodeReference = codeReference, QuantiteDemandee = quantite});
        }
        #endregion
    
        #region Méthodes privées
        /// <summary>
        /// Méthode de recherche du prochain NuméroItem pour la liste en cours
        /// </summary>
        /// <returns>Numéro d'item sur 4 caractères avec des '0' en tête</returns>
        private string GetNextIdItem()
        {
          string resultat = "";
          resultat = (from it in this.Items select it.NumeroItem).Max();
          try
          {
            int res = Int32.Parse(resultat);
            res++;
            resultat = res.ToString().PadLeft(4, '0');
          }
          catch
          {
            resultat = "0001";
          }
          return resultat;
        }
        #endregion
      }
    
    

    Dans le cadre de l'utilisation de l'EDM, quelle est la bonne pratique ?

    Cordialement,

    mercredi 11 mai 2011 12:28
  • Bonjour,

    Je ne suis pas sûr d’avoir compris bien ce que vous voulez dire par « mon objectif était d'enrichir l'expression de l'EDM de contraintes fonctionnelles et de relations or mes contraintes fonctionnelles devraient être implémentées au niveau des get et set des propriétés qui sont dans le Designer.cs ». Vous pouvez compléter votre classe avec des propriétés et méthodes nouvelles, il n’est pas nécessaire de modifier le Designer.cs.

    Concernant votre dernière question, c’est difficile à dire quelle e la meilleure pratique. Je trouve plus élégante compléter la classe BaseListe pour éviter redéfinir certaines propriétés comme Destinataire, par exemple, mais comme je ne connais pas l’ensemble de votre application je ne peux pas dire plus.

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    mercredi 11 mai 2011 12:56
  • En fait, je souhaiterai compléter ma classe en redéfinissant le comportement des propriétés (par le get et set) héritées du designer.cs...

    Par exemple, mise en place de propriétés en lecture seule ou plus problématiquement que le créateur fasse une recherche d'existance dans la base et si l'enregistrement existe déjà que l'objet trouvé dans la base (de type BaseXXX donc) que mon objet courant soit ce BaseXXX agrémenté de mes fonctionnalités (c'était ma problématique de départ en fait...).

    Cordialement,

    mercredi 11 mai 2011 13:24
  • Bonjour,

    En ce cas il est un peu difficile d’utiliser directement les classes EDM (voir une discussion sur ce sujet) et je crois que la classe Liste sans héritage de BaseListe est une bonne solution.

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    mercredi 11 mai 2011 13:46
  • Mais cela oblige à remapper toutes les propriétés, à moins qu'il n'existe un outil pour se faire ?

    Vous pouvez clore le thread, merci.

     

    mercredi 11 mai 2011 13:48
  • Bonjour,

    Vous pouvez aussi clore le thread par marquer comme réponse le post qui vous considérez qu’il vous a aidé ou par transformer la question en discussion si aucune réponse ne répond à vos demandes. En fait, marquer un post comme réponse aide la communauté, vu que d'autres personnes avec le même problème puissent profiter de cette solution.

     

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    mercredi 11 mai 2011 13:59