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

VB.NET Discussion :

Question à propos des DTO's


Sujet :

VB.NET

  1. #1
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut Question à propos des DTO's
    Hello à tous,

    J'ai récemment découvert une série de 3 articles via ce message.

    N'ayant jamais eu de cours d'archi, je me forme sur le tas et cette série d'article tombe à pic !

    Notemment, dans la partie où il traite des DTOParser et notamment des ordinaux afin d'accéder aux éléments des datareaders via leur index plutôt que leur nom (car c'est plus performant).

    Pour un DTO simple, pas de souci. Mais comment fait-on pour un DTO qui contient d'autres DTO's ?

    Prenons par exemple une classe Tel (pour téléphone) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Public Class Tel
        Public Property Id As Integer
        Public Property Type As TypeTel
        Public Property Pays As Pays
        Public Property Num As String
     
        Public Sub New(ByVal id As Integer, ByVal type As TypeTel, ByVal pays As Pays, ByVal num As String)
            Me.Id = id
            Me.Type = type
            Me.Pays = pays
            Me.Num = num
        End Sub
    End Class
    Où TypeTel indique de quel type de téléphone il s'agit (fixe, portable, fax, etc.) et Pays indique le pays histoire d'avoir l'indicatif téléphonique du-dit pays.

    Donc en suivant l'article, je commence vaillamment à créer une classe ParserTel comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Public Class Parser_Tel
     
        Private ord_id As Integer
        Private ord_num As Integer
     
        Public Function PopulateDTO(reader As System.Data.SqlClient.SqlDataReader) As Tel
     
        End Function
     
        Public Sub PopulateOrd(reader As System.Data.SqlClient.SqlDataReader)
     
        End Sub
    End Class
    Mais je bloque pour Pays et TypeTel. Toutes les données nécessaires à la création de ces deux instances se trouvent dans la datareader (pour ne pas devoir refaire un accès db pou récupérer le pays et le type sur base de leur Id).
    Faut-il faire appel au parser du DTO Pays dans la fonction PopulateDTO ??

    J'espère avoir été clair

  2. #2
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par Kropernic Voir le message
    Mais comment fait-on pour un DTO qui contient d'autres DTO's ? Faut-il faire appel au parser du DTO Pays dans la fonction PopulateDTO ??
    Oui il le faut, sinon ça t'oblige à implémenter deux fois le code nécessaire à la création d'un objet PaysDTO, ce qui est une perte de temps, et qui va te compliquer la vie lors des maintenances
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  3. #3
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    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
    Public Class Parser_Tel
     
        Private ord_id As Integer
        Private ord_num As Integer
     
        Public Function PopulateDTO(reader As System.Data.SqlClient.SqlDataReader) As Tel
            Dim tel As New Tel
            tel.Id = reader.GetInt32(ord_id)
            tel.Num = reader.GetString(ord_num)
     
            Dim parser As New Parser_Pays
            parser.PopulateOrd(reader)
            tel.Pays = parser.PopulateDTO(reader)
     
            Return tel
        End Function
     
        Public Sub PopulateOrd(reader As System.Data.SqlClient.SqlDataReader)
            ord_id = reader.GetOrdinal("TEL_ID")
            ord_num = reader.GetOrdinal("TEL_NUM")
        End Sub
    End Class
    Je dois encore faire pour le type mais pour le pays, ça donne quelque chose dans ce goût là non ?

  4. #4
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Billets dans le blog
    3
    Par défaut
    Oui tout à fait, comme ça le jour où tu modifies la structure de ton objet Pays, tu as juste à modifier la classe Parser_Pays et le tour est joué, tu n'auras pas besoin de répercuter ces modifications ailleurs.

    Petit conseil au passage, n'oublie pas de "blinder" tes parser, en vérifiant que les valeurs sont bien dans le SqlDataReader. Si elles n'y sont pas, prévois de mettre une valeur par défaut, ou de lancer un traitement particulier, ou une erreur.
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  5. #5
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    Oki doki !

    Merci du conseil

  6. #6
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    Pas si résolu que ça finalement.

    Mais plus rien à voir avec l'architecture.

    Tout l'intérêt d'utiliser les ordinaux est d'accéder aux items via l'index en utilisant la méthode GetXXXX du datareader où XXXX est le type approprié (ça évite le castint également).

    Seulement pour les objets de type Integer, il existe juste GetInt32 mais ça colle pas.... Je trouve ça un peu moche d'aller foutre un cast là alors que tout le reste fonctionne sans cast.

    Une solution alternative et élégante ? Suis-je passé à côté de quelque chose ?


    EDIT : J'étais bien passé à côté de quelque chose... La colonne que je récupère avec GetInt32 est de type Tinyint dans SQL SERVER

  7. #7
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Billets dans le blog
    3
    Par défaut
    Tu peux voir le mapping entre les types SQL Server et les types C# ici : http://msdn.microsoft.com/en-us/library/cc716729.aspx
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  8. #8
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    Citation Envoyé par DotNetMatt Voir le message
    Tu peux voir le mapping entre les types SQL Server et les types C# ici : http://msdn.microsoft.com/en-us/library/cc716729.aspx
    Hello,

    Je vais enfin voir le lien et je découvre que pour chaque méthode GetXXX, il a une version GetSqlXXX.

    Quelles différences entre les deux ?

    Perso, j'ai remarqué que je ne peux pas mettre le résultat de GetSqlInt16 dans un variable de type Integer mais pas de souci avec GetInt16.

    Faut-il en préféré l'une par rapport à l'autre ? (j'imagine que ça dépend de l'usage mais bon...)

  9. #9
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Billets dans le blog
    3
    Par défaut
    Il n'y a pas beaucoup de différence entre les deux. GetInt32 fait appel à GetSqlInt32. On peut le voir en décompilant :

    Méthode GetSqlInt32 :
    Code VB.NET : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Public Function GetSqlInt32(i As Integer) As SqlInt32
    	Return DirectCast(Me.PrepareSQLRecord(i), SqlInt32)
    End Function

    Méthode GetInt32 :
    Code VB.NET : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Public Function GetInt32(i As Integer) As Integer
    	Dim num1 As SqlInt32 = Me.GetSqlInt32(i)
    	Return num1.Value
    End Function

    Si tu utilises GetSqlInt16 il ne faut pas oublier d'appeler la propriété Value afin de récupérer l'objet de type Int16.
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  10. #10
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    Citation Envoyé par DotNetMatt Voir le message
    Si tu utilises GetSqlInt16 il ne faut pas oublier d'appeler la propriété Value afin de récupérer l'objet de type Int16.
    Voilà ce qui est important je pense !

    Sinon, comment tu fais pour décompiler et voir comment est faite une méthode ?

  11. #11
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Billets dans le blog
    3
    Par défaut
    A titre personnel j'utilise .NET Reflector pour décompiler, de Lutz Roeder, aujourd'hui vendu par Red-Gate : http://www.red-gate.com/products/dot...ent/reflector/

    Il suffit de l'utiliser pour ouvrir l'assembly contenant la méthode que tu veux voir, et il t'affiche le code, soit en C#, soit en VB.NET, soit en IL
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  12. #12
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    J'ai encore une question ...

    Pour le cas de l'héritage ce coup-ci.

    Je plante le décor...

    Mon application traite de gift-cheque et gift-cartes. J'ai donc les classes suivante :

    1. Gift :
      • Id Integer
      • Prefix String
      • Serial Integer

    2. Carte (hérite de Gift):
      • Type TypeCarte
      • Rechargeable Boolean

    3. Cheque (hérite de Gift):
      • Type Integer
      • Year Integer


    Jusqu'ici, je ne travaillais pas avec les parser. J'ai donc dans ma classe DAL_GIFT, une fonction nommée SelectGift qui retourne une liste de Gift. Mais lors de l'ajout d'un gift à la liste, j'ajoute une carte ou un chèque (le teste se fait sur le préfix (24 pour les cartes, le reste sont des chèques)).


    Si on suit l'article, il y a une fonction dans DAL_BASE qui renvoie une liste de DTO nommée GetDTOList(Of T as DTOBase) qui renvoit une liste (de T).


    Je ne vois pas comment l'utiliser dans ce cas-ci... J'ai besoin que les objets dans la liste soient du bon type et avec toutes leurs informations... :-/

    Pour info, voici le code de la fonction SelectGift actuelle:
    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
        Public Shared Function SelectGift(ByVal gft_id As Integer) As List(Of GIFT_MANAGER_DTO.Gift)
            Try
                Dim result As New List(Of GIFT_MANAGER_DTO.Gift)
     
                Using cnx As SqlConnection = CreateConnexion()
                    Using cmd As SqlCommand = cnx.CreateCommand
                        cmd.CommandType = CommandType.StoredProcedure
                        cmd.CommandText = "UP_GIFT_SELECT"
     
                        If Not gft_id = -1 Then
                            Dim prm_gft_id As New SqlParameter
                            prm_gft_id.ParameterName = "@GFT_ID"
                            prm_gft_id.Direction = ParameterDirection.Input
                            prm_gft_id.SqlDbType = SqlDbType.Int
                            prm_gft_id.SqlValue = gft_id
                            cmd.Parameters.Add(prm_gft_id)
                        End If
     
                        cnx.Open()
     
                        Using dr As SqlDataReader = cmd.ExecuteReader
                            While dr.Read
                                If CInt(dr.Item("PREFIX")) = 24 Then 'carte
                                    result.Add(New GIFT_MANAGER_DTO.Carte(CInt(dr.Item("GFT_ID")),
                                                                          GIFT_MANAGER_DAL.TypeCarte.SelectTypeCarte(CInt(dr.Item("TYPE")), Nothing)(0),
                                                                          CInt(dr.Item("SERIAL")),
                                                                          CBool(dr.Item("RECHARGEABLE"))))
                                Else 'cheque
                                    result.Add(New GIFT_MANAGER_DTO.Cheque(CInt(dr.Item("ID")),
                                                                           CStr(dr.Item("PREFIX")),
                                                                           CStr(dr.Item("TYPE")),
                                                                           CStr(dr.Item("YEAR")),
                                                                           CInt(dr.Item("SERIAL"))))
                                End If
                            End While
                        End Using
                    End Using
                End Using
     
                Return result
            Catch ex As Exception
                Throw ex
            End Try
        End Function
    Ce n'est sûrement pas parfait mais ça tourne jusqu'ici .
    J'essaie donc d'adapter cela en suivant l'article mais le fait de faire un test sur la colonne PREFIX me dérange...

  13. #13
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Billets dans le blog
    3
    Par défaut
    Je pense que dans ce cas il n'y a pas d'autre solution que de faire un test...
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  14. #14
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Par défaut Comment faire une fabrique générique de classe ?
    Bonjour,

    Ayant vu ce fil, j'ai voulu utiliser le principe.

    J'aurai voulu rendre ceci plus générique, mais je butte sur un problème.

    J'ai une classe abstraite pour les DTO (bib DTO)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Public MustInherit Class DTOParser
        Public MustOverride Function PopulateDTO(ByVal reader As DbDataReader) As clsDTOBase
        Public MustOverride Sub PopulateOrdinals(ByVal reader As DbDataReader)
    End Class
    Je cré des classes qui hérite de DTOParser (comme dans les liens sur les DTO)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MustInherit Class DTOParser_Person
        Inherits DTOParser
    '...
    J'ai des classes pour utiliser un DTO typé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        Public Function GetPersonId(ByVal PersonId As String) As PersonDTO
            DALApp.AjouteParam("PersonId", DbType.String, PersonId)
            Return DALApp.GetSingleDTO(Of PersonDTO)("select * from personnes where PersonId = ?")
        End Function
    Cette méthode GetSingleDto fait partie de ma DAL (bib DAL) et c'est ici que je souhaite utiliser une fabrique de DTO générique
    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
        Public Function GetSingleDTO(Of T As clsDTOBase)(ByVal Requete As String) As T 'where T as clsdtobase
            Dim UnDTO As T = Nothing
            Dim Reader As DbDataReader
            Try
                Using Reader
                    If ExecuterReader(Requete, Reader) = 0 Then
                        If Reader.HasRows Then
                            Reader.Read()
                            Dim parser As DTOParser
                            parser = DTOParserFactory.GetParser(GetType(T))
                            'parser = CType(DTOParserFactory.CreInstanceDTO("PersonDTO"), DTOParser)
                            'parser = DTOFabriqueAnalyseur.GetAnalyseur(GetType(T))
                            parser.PopulateOrdinals(Reader)
                            UnDTO = DirectCast(parser.PopulateDTO(Reader), T)
                        End If
    Dans les exemples des liens les noms sont en dur. Cela ne me convient pas puisque ma méthode sera placé dans la bib DTO et ne connais donc pas les noms des classes qui seront crées dans l'appli qui l'utilisera.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Public NotInheritable Class DTOParserFactory
        Public Shared Function GetParser(ByVal DTOType As System.Type) As DTOParser
            Select Case DTOType.Name
                Case "PersonDTO"
                    Return New DTOParser_Person()
                    Exit Select
                Case "PostDTO"
                    'Return New DTOParser_Post()
                    Exit Select
    '...
            End Select
            Throw New Exception("Unknown Type")
        End Function
    D'ou ma question comment faire une fabrique générique de classe ? fabrique qui prendrait un type T (classe quelconque) et qui renverrai une instance de cette classe typé (ex : PersonDTO)


    Je n'ai rien trouvé de concret sur le net malgrès différentes recherche. J'ai essayé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Public NotInheritable Class DTOFabriqueAnalyseur(Of T As {Class, New})
        Private Sub New()
        End Sub
        Public Shared Function GetAnalyseur(Of _T As {Class, New})() As DTOParser
            Dim dto_parser As Type = GetType(_T)
            Dim typeArgs As Type() = {GetType(DTOParser)}
            Dim ClasseDyn As Type = dto_parser.MakeGenericType(typeArgs)
            Return Activator.CreateInstance(ClasseDyn)
        End Function
    End Class
    Mais j'ai des problème de convertion de type.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Public NotInheritable Class DTOParserFactory
        Public Shared Function CreInstanceDTO(ByVal typeName As String) As Object
            For Each assembly As Reflection.Assembly In AppDomain.CurrentDomain.GetAssemblies()
                For Each type As Type In assembly.GetTypes()
                    If (typeName = type.Name) OrElse (typeName = type.FullName) Then
                        Return Activator.CreateInstance(type)
                    End If
                Next
            Next
            Return Nothing
        End Function
    End Class
    mais le debbogger se perd. [Edit] sur la ligne If (typeName = type.Name) OrElse (typeName = type.FullName) Then [/Edit]


    Je cherche depuis un moment, mais je ne trouve pas. Si vous avez une idée ou une solution, je suis à l'écoute.

    A+, Hervé.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  15. #15
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Par défaut
    Bien, j'ai trouvé une solution.

    Dans la bibliothèque DTO
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ''' <summary>DTOParserFactory : pour obtenir un objet analyseur (parser).</summary>
    ''' <remarks></remarks>
    Public NotInheritable Class DTOParserFactory
        ''' <summary>Cré une instance d'une classe quelconque.</summary>
        ''' <param name="IdMembre">Identifiant du membre de classe dans l'assembly.</param>
        ''' <returns>Une instance de la classe trouvé.</returns>
        ''' <remarks></remarks>
        Public Shared Function GetInstanceDTO(ByVal IdMembre As String) As Object
            Dim strAQN As String = IdMembre
            Return Type.GetType(strAQN).InvokeMember(strAQN, System.Reflection.BindingFlags.CreateInstance, Nothing, Nothing, Nothing)
        End Function
    Dans la bibliothèque DAL
    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
        Public Function GetSingleDTO(ByVal IdMembre As String, ByVal Requete As String) As clsDTOBase
            Dim Reader As DbDataReader
            Try
                Using Reader
                    If ExecuterReader(Requete, Reader) = 0 Then
                        If Reader.HasRows Then
                            Reader.Read()
                            Dim parser As Object
                            parser = DTOParserFactory.GetInstanceDTO(IdMembre)
                            'parser = DTOParserFactory.GetParser(GetType(T))
                            'parser = CType(DTOParserFactory.CreInstanceDTO("PersonDTO"), DTOParser)
                            'parser = DTOFabriqueAnalyseur.GetAnalyseur(GetType(T))
                            parser.PopulateOrdinals(Reader)
                            Return parser.PopulateDTO(Reader)
                        End If
    Au sein de l'appli, les accés à la DAL
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Public Class PersonDB
        Inherits clsDALAppli
     
        Public Function GetPersonId(ByVal PersonId As String) As PersonDTO
            DALApp.AjouteParam("PersonId", DbType.String, PersonId)
            Return DALApp.GetSingleDTO((New DTOParser_Person).GetType.AssemblyQualifiedName, "select * from personnes where PersonId = ?")
        End Function
     
        Public Function GetPersonByEmail(ByVal email As String) As PersonDTO
            DALApp.AjouteParam("email", DbType.String, email)
            Return DALApp.GetSingleDTO((New DTOParser_Person).GetType.AssemblyQualifiedName, "select * from personnes where email = ?")
        End Function
    Appel
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            Dim PersDb As PersonDB = New PersonDB
            Dim p As PersonDTO = PersDb.GetPersonByEmail("Email")
            MessageBox.Show(p.personid)
    Mais cela rique de ne pas être performant vu que l'on fait appel à la réflexion.

    Je recherche donc une autre solution.
    Note: je m'étais un peu mélangé avec les classes dans mon post précédant, je vais revérifier cela pour voir si une autre solution fonctionnerait)

    Merci à ceux qui suivent. Et si vous avez une idée n'hésitez pas à en faire part.

    A+, Hervé.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  16. #16
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Billets dans le blog
    3
    Par défaut
    C'est clair que c'est pas forcément évident à suivre

    De mon côté j'utilise quelque chose qui ressemble à ça :
    Code VB.NET : 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
     
    Friend Shared Function GetParser(typeName As String) As DTOParser
     	Dim currentAssembly = Assembly.GetExecutingAssembly()
      	For Each type As Type In currentAssembly.GetTypes()
    		' On supprime le préfixe "DTO" pour ne garder que le nom de l'entité
    		Dim entityName = typeName.Replace("DTO", String.Empty)
    		If type.Name.Contains(entityName) OrElse type.FullName.Contains(entityName) Then
    			' On applique le préfixe "DTOParser_" afin de mapper l'entité sur son parser correspondant
     			Dim newValue = "DTOParser_" & entityName
     			Dim newType = Activator.CreateInstance(currentAssembly.FullName, currentAssembly.GetName().Name + "." & newValue, Nothing)
     
      			Return DirectCast(newType.Unwrap(), DTOParser)
    		End If
    	Next
     
      	Return Nothing
    End Function
    Cette solution oblige à respecter quelques règles de nommage...

    Appel depuis DALBase :
    Code VB.NET : Sélectionner tout - Visualiser dans une fenêtre à part
    Dim parser As DTOParser = DTOParserFactory.GetParser(GetType(T).Name)
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  17. #17
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Par défaut
    Merci de suivre,

    Je vais étudier cette piste.

    A+, Hervé.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  18. #18
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Par défaut
    Je vais essayer de résumer et simplifier.

    Dans la bibbliothèque DataTransfertObject
    Une classe abstraite définie un parser afin d'être réféencer dans la DAL
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Public MustInherit Class DTOParser
        ''' <summary>Méthode abstraite de lecture des données.</summary>
        Public MustOverride Function PopulateDTO(ByVal reader As DbDataReader) As clsDTOBase
        ''' <summary>Méthode abstraite de recherche des ordinaux de chaque colonne.</summary>
        Public MustOverride Sub PopulateOrdinals(ByVal reader As DbDataReader)
    End Class
    Dans une classe DTOParserFactory, une méthode permet de récupérer une instance d'une dérivé de cette classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Public NotInheritable Class DTOParserFactory
        Public Shared Function GetParser(Of T As {DTOParser, New})(ByVal DTOType As System.Type) As DTOParser
            Return New T
    Dans la bibbliothèque DataAccessLayer
    Une méthode permet de lire les données
    Il faut qu'elle est une instance de la classe dérivée de DTOParser : DTOParser_Person créer par DTOParserFactory.GetParser (1)
    Elle lit les données (2)
    Et alimente DTOParser_Person avec les données (3)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     Public Function GetSingleDTO(Of T As DTOParser)(ByVal Requete As String) As T
    parser = DTOParserFactory.GetParser(T) ' (1)
    ' ExecuteReader ' (2) simplifier pour ne pas surcharger
                            parser.PopulateOrdinals(Reader) ' (3) pour acces rapide
                            Return parser.PopulateDTO(Reader) ' (3)
    Au sein de l'appli, les accés à la DAL
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Return DALApp.GetSingleDTO(DTOParser_Person)("select * from personnes where PersonId = ?")
    DTOParser_Person étant dérivé de DTOParser
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Class DTOParser_Person
        Inherits DTOParser
    DTOParser_Person contient uniquement les mêmes métodes (implémentées) que DTOParser (qui lui n'a que la définition)

    Le probléme se situe au passage d'une classe générique dans Public Function GetSingleDTO(Of T As DTOParser) et la retourner sous la forme reçue.

    Plus précisément.
    Parceque la méthode DTOParserFactory.GetParser(T) ne peut connaître qu'une classe de base DTOParser (plus générique), mais recoit une classe dérivé de cette classe de base DTOParser_Person et renvoie une instance de cette dernière.

    Je souhaite éviter la réflexion qui en terme de performance n'est pas terrible.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  19. #19
    Membre expérimenté
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Par défaut
    Je n'ai pas compris le problème je crois...

    Où est le souci que le nom des types de DTO soient en dur dans lafactory ? Celle-ci ainsi que les parsers qu'elle retourne se trouvent dans le même projet. On connait donc à tout moment le nom des DTO qui existent.

  20. #20
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Par défaut
    Citation Envoyé par Kropernic Voir le message
    Je n'ai pas compris le problème je crois...

    Où est le souci que le nom des types de DTO soient en dur dans lafactory ? Celle-ci ainsi que les parsers qu'elle retourne se trouvent dans le même projet. On connait donc à tout moment le nom des DTO qui existent.
    Non,
    J'ai placé les éléments de base des DTO dans une bibliothéque afin de rendre cela plus générique.

    Seule les classe dérivés sont dans mon appli. Ex : DTOParser_Person

    La fabrique est elle aussi dans la bibliothéque et ne connais donc pas les classes qui seront dérivées dans les différentes appli qui l'utiliseront. Et c'est là que c'est plus délicat.

    J'ai trouvé une solution mais avec de la réflexion, ce qui n'est pas intéressant en terme de performance.

    C'est pour cela que je recherche une solution avec création d'instance de classe de façon générique.


    En gros : la méthode de fabrique reçoit un type de classe, et renvoie une instance de cette classe utilisable.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

Discussions similaires

  1. question à propos des containeurs
    Par bountykiller dans le forum C++
    Réponses: 4
    Dernier message: 02/10/2005, 14h21
  2. Question à propos des états
    Par rangernoir dans le forum IHM
    Réponses: 4
    Dernier message: 30/09/2005, 15h38
  3. Question à propos des compilateurs
    Par elf dans le forum Autres éditeurs
    Réponses: 4
    Dernier message: 20/07/2005, 18h00
  4. Question à propos des niveaux de transaction
    Par davy.g dans le forum Oracle
    Réponses: 3
    Dernier message: 18/01/2005, 16h31
  5. Une question à propos des thread
    Par tscoops dans le forum C++Builder
    Réponses: 4
    Dernier message: 07/11/2003, 15h03

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