Ecco il mio primo post, nel mio primo blog... 
Oggi volevo trattare con voi Parsing dei file di Mapping creati per NHibernate. 
Innanzitutto, a cosa può servire? Nel mio caso ad esempio per effettuare delle ricerche utilizzando le expression di NHibernate in modo tale da poter generalizzare un form che, passando una entity specifica, mi indichi tutte le proprietà ad essa associate. 
Iniziamo dunque dalla prima classe, presa direttamente dalla seguente pagina web :
http://weblogs.domain-driven.net/default,date,2006-09-25.aspx 
Quindi convertiamo la classe in VB.NET e successivamente l’estendiamo.
 
TypeMappingParser.vb 
 
Imports System
Imports System.Collections
Imports System.Reflection
Imports System.Reflection.Emit
 
Imports NHibernate
Imports NHibernate.Metadata
Imports NHibernate.Type
Imports NHibernate.Bytecode
Imports NHibernate.Mapping
Imports NHibernate.Loader
 
Public Enum AssociationType
    OneToOne
    OneToMany
    ManyToOne
    Component
End Enum
 
Public Class TypeMappingParser
 
    Private _typeMappings As Hashtable
 
    Public Sub New(ByVal factory As ISessionFactory)
        ParseMappings(factory)
    End Sub
 
    Public Function GetTypeMappingInfo(ByVal typeName As String) As TypeMappingInfo
        Return CType(_typeMappings(typeName), TypeMappingInfo)
    End Function
 
    Private Sub ParseMappings(ByVal factory As ISessionFactory)
        _typeMappings = New Hashtable()
        IdentifyMappedTypes(factory)
        ParseMappedTypes(factory)
    End Sub
 
    Private Sub IdentifyMappedTypes(ByVal factory As ISessionFactory)
 
        For Each type As Type In factory.GetAllClassMetadata().Keys
 
            'Dim icmd As IClassMetadata = factory.GetClassMetadata(type)
            Dim typeMappingInfo As TypeMappingInfo = New TypeMappingInfo(type)
            _typeMappings.Add(type.Name, typeMappingInfo)
        Next
    End Sub
 
    Private Sub ParseMappedTypes(ByVal factory As ISessionFactory)
 
        For Each type As Type In factory.GetAllClassMetadata().Keys
            ParsePropertiesAndAssociations(factory, type)
        Next
 
    End Sub
 
    Private Sub ParsePropertiesAndAssociations(ByVal factory As ISessionFactory, ByVal type As Type)
 
        Dim propertyIndex As Integer = 0
 
        Dim classMeta As IClassMetadata = CType(factory.GetAllClassMetadata()(type), IClassMetadata)
        Dim containingTypeMappingInfo As TypeMappingInfo = GetTypeMappingInfo(type.Name)
 
        For Each propertyType As IType In classMeta.PropertyTypes
 
            If (propertyType.IsAssociationType) Then
 
                ParseEntity(factory, containingTypeMappingInfo, propertyType, classMeta.PropertyNames(propertyIndex))
 
            ElseIf (propertyType.IsComponentType) Then
 
                ParseComponentType(factory, containingTypeMappingInfo, propertyType, classMeta.PropertyNames(propertyIndex))
 
            Else
                ParseValue(containingTypeMappingInfo, propertyType, classMeta.PropertyNames(propertyIndex))
            End If
            propertyIndex += 1
        Next
    End Sub
 
    Private Sub ParseComponentType(ByVal factory As ISessionFactory, ByVal containingTypeInfo As TypeMappingInfo, ByVal propertyType As IType, ByVal propertyName As String)
 
        If (Not _typeMappings.Contains(propertyType.Name)) Then
 
            Dim desc As TypeMappingInfo = New TypeMappingInfo(propertyType.ReturnedClass)
            _typeMappings.Add(propertyType.Name, desc)
 
            Dim entityPropInfo As New EntityPropertyInfo( _
                    containingTypeInfo, _
                    propertyType.ReturnedClass, _
                    propertyName, _
                    GetAssociationType(propertyType, False))
 
            'entityPropInfo.TypeMappingInfo = desc
 
            containingTypeInfo.AddProperty(entityPropInfo)
 
            Dim compType As IAbstractComponentType = CType(propertyType, IAbstractComponentType)
 
            For index As Integer = 0 To compType.PropertyNames.Length - 1
 
                Dim subType As IType = compType.Subtypes(index)
                If (subType.IsAssociationType) Then
 
                    ParseEntity(factory, desc, subType, compType.PropertyNames(index))
 
                ElseIf (subType.IsComponentType) Then
 
                    ParseComponentType(factory, desc, subType, compType.PropertyNames(index))
 
                Else
 
                    ParseValue(desc, subType, compType.PropertyNames(index))
                End If
            Next
 
        Else
 
            containingTypeInfo.AddProperty( _
                New EntityPropertyInfo(containingTypeInfo, _
                 propertyType.ReturnedClass, _
                 propertyName, _
                 GetAssociationType(propertyType, False)))
        End If
    End Sub
 
    Private Sub ParseValue(ByVal containingTypeMappingInfo As TypeMappingInfo, ByVal propertyType As IType, ByVal propertyName As String)
 
        Dim info As ValuePropertyInfo = New ValuePropertyInfo(containingTypeMappingInfo, _
             propertyType.ReturnedClass, _
             propertyName)
 
        containingTypeMappingInfo.AddProperty(info)
    End Sub
 
    Private Sub ParseEntity(ByVal factory As ISessionFactory, ByVal containingTypeInfo As TypeMappingInfo, _
            ByVal propertyType As IType, ByVal propertyName As String)
 
        If (propertyType.IsEntityType) Then
 
            Dim info As EntityPropertyInfo = _
                New EntityPropertyInfo(containingTypeInfo, _
                 propertyType.ReturnedClass, _
                 propertyName, _
                 GetAssociationType(propertyType, False))
 
            containingTypeInfo.AddProperty(info)
 
        Else
            Dim collectionMeta As ICollectionMetadata = _
                            factory.GetCollectionMetadata((CType(propertyType, CollectionType)).Role)
 
 
 
            If (TypeOf collectionMeta.ElementType Is ComponentType) Then
 
                Dim componentType As ComponentType = CType(collectionMeta.ElementType, ComponentType)
 
                Dim info As EntityPropertyInfo = _
                    New EntityPropertyInfo(containingTypeInfo, _
                     componentType.ReturnedClass, _
                     propertyName, _
                     GetAssociationType(componentType, True))
 
                containingTypeInfo.AddProperty(info)
 
            ElseIf (TypeOf collectionMeta.ElementType Is ManyToOneType) Then
 
                Dim info As EntityPropertyInfo = New EntityPropertyInfo( _
                    containingTypeInfo, _
                    collectionMeta.ElementType.ReturnedClass, _
                    propertyName, _
                    GetAssociationType(collectionMeta.ElementType, True))
                containingTypeInfo.AddProperty(info)
            Else
                Throw New ApplicationException("Collection type " & collectionMeta.ElementType.Name & " was not recognized")
            End If
        End If
    End Sub
 
    Private Function GetAssociationType(ByVal type As IType, ByVal isCollection As Boolean) As AssociationType
 
        If (TypeOf type Is ManyToOneType AndAlso isCollection) Then
            Return AssociationType.OneToMany
 
        ElseIf (TypeOf type Is ManyToOneType) Then
            Return AssociationType.ManyToOne
        ElseIf (TypeOf type Is OneToOneType) Then
            Return AssociationType.OneToOne
        Else
            Return AssociationType.OneToOne
        End If
    End Function
 
End Class
 
Si può notare che, nel costruttore della classe si passi l'ISessionFactory; tramite questa semplice interfaccia, disponibile in NHibernate, si riesce a sapere qualunque cosa di qualunque entity mappata correttamente nel nostro assembly.
Inizierà dunque il parsing veri e proprio costruendosi una struttura identificando da prima le varie entity e quindi le varie proprietà di ognuna di esse stabilendo le eventuali relazioni tra i vari oggetti. 
Sucessivamente per avere le informazioni dell'entity A, ad esempio, basta richiamare il metodo GetTypeMappingInfo("A") il quale restituirà un oggetto di tipo TypeMappingInfo
 
TypeMappingInfo.vb 
 
Public Class TypeMappingInfo
 
 
    Private _type As Type
    Private _listProperty As IList(Of IPropertyInfo)
 
    Sub New(ByVal type As Type)
        Me._type = type
 
        Me._listProperty = New List(Of IPropertyInfo)
    End Sub
 
    Public Sub AddProperty(ByVal obj As IPropertyInfo)
        Me._listProperty.Add(obj)
    End Sub
 
    Public ReadOnly Property ListProperty() As IList(Of IPropertyInfo)
        Get
            Return Me._listProperty
        End Get
    End Property
 
    Public ReadOnly Property TypeClass() As System.Type
        Get
            Return Me._type
        End Get
    End Property
 
    Public Overrides Function ToString() As String
        Return Me._type.Name
    End Function
End Class
 
Questa classe è il contenitore delle informazioni dell'entity richiesta. Oltretutto tramite la property TypeClass posso creare nuovi oggetti del tipo indicato. 
Nel prossimo post vedo di allegare anche il resto del codice, con una semplice spiegazione del funzionamento dello stesso e del suo possibile utilizzo. 
Un saluto a tutti
Alberto B.B.