2010-03-15 4 views
4

Je crée un modèle de domaine dans lequel les entités ont souvent (mais pas toujours) un membre de type ActionLog.Mapper l'entité NHibernate à plusieurs tables en fonction du parent

ActionLog est une classe simple qui permet une piste d'audit des actions effectuées sur une instance. Chaque action est enregistrée en tant qu'instance ActionLogEntry.

ActionLog est mis en œuvre (environ) comme suit:

public class ActionLog 
{ 
    public IEnumerable<ActionLogEntry> Entries 
    { 
     get { return EntriesCollection; } 
    } 

    protected ICollection<ActionLogEntry> EntriesCollection { get; set; } 

    public void AddAction(string action) 
    { 
     // Append to entries collection. 
    } 
} 

Ce que je voudrais est de réutiliser cette classe parmi mes entités et ont les entrées carte aux tables différentes en fonction de quelle classe ils sont connectés contre . Par exemple:

public class Customer 
{ 
    public ActionLog Actions { get; protected set; } 
} 

public class Order 
{ 
    public ActionLog Actions { get; protected set; } 
} 

Cette conception me convient dans l'application, mais je ne vois pas de façon claire pour cartographier ce scénario à une base de données avec NHibernate.

J'utilise généralement Fluent NHibernate pour ma configuration, mais je suis heureux d'accepter les réponses en général HBM xml.

+0

Y a-t-il une raison particulière pour laquelle vous souhaitez que chaque type d'action passe à une table distincte? –

+0

C'est un ajustement plus naturel pour une structure relationnelle. Relationnellement, vous avez les tables 'Customers' et' CustomerActionLogEntries'. Parallèlement à cela, vous avez des tables Orders et OrderActionLogEntries. Actuellement, ma solution consiste à avoir une seule table 'ActionLogEntries' et à utiliser des tables jointes avec des relations Many-to-Many dans NHibernate. C'est un peu trop normalisé à mon goût, nécessitant des jointures partout pour obtenir des données significatives. –

+0

Avez-vous déjà obtenu une résolution pour cela? Je suis sur le point de poster la même question. – Origin

Répondre

3

je le même problème et était sur le poste de la même question dans l'espoir d'une réponse - mais je trouve la solution à l'aide du NH IRC canal sur FreeNode.

Mon scénario comporte un document. Diverses choses auront des documents - comme des rapports, des éléments, etc. La seule différence entre Report.Documents et Item.Documents est que le document a une référence à son propriétaire, et il est mappé à une table différente.

La solution pour cette situation est principalement accomplie par .Net. Bien que - je ne pense pas que cette solution serait possible avec les mappages XML.

La classe de document:

Public Class Document 
    Public Overridable Property DocumentId As Integer 
    Public Overridable Property Directory As String 
    Public Overridable Property Name As String 
    Public Overridable Property Title As String 
    Public Overridable Property Revision As String 
    Public Overridable Property Description As String 
    Public Overridable Property Owner As String 
    Public Overridable Property UploadedBy As String 
    Public Overridable Property CreationDate As Date 
    Public Overridable Property UploadDate As Date 
    Public Overridable Property Size As Int64 
    Public Overridable Property Categories As String 
End Class 

Ensuite, nous héritons de cette classe pour chacun de nos types de documents supplémentaires:

Public Class ReportDocument 
    Inherits Document 
    Public Overridable Property Report As Report 
End Class 

Public Class ItemDocument 
    Inherits Document 
    Public Overridable Property Item As Item 
End Class 

est ici où la "magie" se produit. Nous allons créer un mappage générique qui nécessite que l'objet utilisé hérite de la classe Document. De cette manière, NHibernate fluide peut toujours trouver toutes les propriétés sur les objets qui héritent du document.

Public Class GenericDocumentMapping(Of T As Document) 
    Inherits ClassMap(Of T) 
    Public Sub New() 
     Id(Function(x) x.DocumentId) 
     Map(Function(x) x.Directory) 
     Map(Function(x) x.Name) 
     Map(Function(x) x.Title).Not.Nullable() 
     Map(Function(x) x.Revision) 
     Map(Function(x) x.Description) 
     Map(Function(x) x.Owner) 
     Map(Function(x) x.UploadedBy) 
     Map(Function(x) x.CreationDate).Not.Nullable() 
     Map(Function(x) x.UploadDate).Not.Nullable() 
     Map(Function(x) x.Size) 
     Map(Function(x) x.Categories) 
    End Sub 
End Class 

Vous remarquerez que cette classe n'a pas de référence à quelle table il est mis en correspondance, ni l'objet parent que chaque version différente utilisera. Maintenant, nous utilisons ce mappage générique pour chacun de nos types spéciaux, et spécifions la table et mappons l'objet parent que nous avons créé dans chaque type de classe que nous avons créé.

Public Class ReportDocumentMapping 
    Inherits GenericDocumentMapping(Of ReportDocument) 
    Public Sub New() 
     MyBase.New() 
     References(Function(x) x.Item).Column("ReportID") 
     Table("ReportDocuments") 
    End Sub 
End Class 

Public Class ItemDocumentMapping 
    Inherits GenericDocumentMapping(Of ItemDocument) 
    Public Sub New() 
     MyBase.New() 
     References(Function(x) x.Item).Column("ItemID") 
     Table("ItemDocuments") 
    End Sub 
End Class 

Je pense que cette méthode réduit beaucoup de code. Maintenant, si vous voulez apporter des changements radicaux au type de document - vous devez seulement modifier la classe Document, et la classe GenericDocumentMapping.

Dans ma situation - je ne fais que mapper des documents à une table spécifique.Ceci est fait de la même manière que les autres - hériter du GenericDocumentMapping et spécifier la table. La seule différence est que je ne référence pas un objet parent.

Public Class DocumentMapping 
    Inherits GenericDocumentMapping(Of Document) 
    Public Sub New() 
     MyBase.New() 
     Table("Documents") 
    End Sub 
End Class 
+0

Cette réponse présente un compromis raisonnable et une approche assez intelligente du problème. –

0

youu peut utiliser se joindre à la carte à plus de la table

Questions connexes