2011-07-01 1 views
3

Je construis une application sur une base de données héritée qui stocke des valeurs de recherche dans une table générique (en fait, elle est contenue dans quatre tables différentes.) Cela signifie que les tables d'entité stockent le "id" de la valeur de recherche et les tables de métadonnées contiennent la "description" de cette valeur.Entité de mappe NHibernate vers une table de recherche générique

Les tables de métadonnées sont décomposées comme suit:

  • TableInfo
  • ColumnInfo
  • Businessinfo
  • LookupDescriptionInfo

Pour obtenir la description de recherche, vous rejoignez les quatre tables et spécifiez le nom de la table, le nom de la colonne et l'identifiant de recherche. La table d'informations de description de recherche contient deux colonnes --- une pour les valeurs de texte et une pour les valeurs numériques. Je voudrais avoir une classe distincte pour chaque type de recherche (par exemple, ma classe Widget aurait une relation plusieurs-à-un avec "WidgetType" basé sur la valeur Widget.WidgetTypeId.) Quelles sont les stratégies pour accomplir cela? Le modèle de données est utilisé par plus de 1000 programmes RPG, il ne peut donc pas être modifié.

Répondre

5

J'ai eu presque exactement le même problème que vous et j'ai trouvé les solutions suivantes viables.

Créer Voir SQL

-- I'm guessing at the table join structure here 
create view LookupView 
as 
select t.TableName, 
    ci.ColumnName, 
    bi.Id, --This ID column needs to be the one used as the FK from other tables 
    bi.*, --Or whatever columns you need 
    coalesce(di.TextDescription, di.NumericDescription) as Description 
from TableInfo t 
join ColumnInfo ci on t.Id=ci.TableId 
join BusinessInfo bi on bi.Id=ci.BusinessId 
join LookupDescriptionInfo di on di.id=ci.id 

Créer la base de recherche de classe

public class Lookup { 
    public virtual string Tablename {get; set;} 
    public virtual string ColumnName {get; set;} 
    public virtual string Description {get; set;} 
    public virtual int Id {get; set;} 
    //Other BusinessInfo properties 
} 

Créer un hérité LookupClass

public class ArmourLookup : Lookup{} 

Utilisez la classe ArmourLookup sur vos objets métier.

public class HeroArmour{ 
    //Usual properties etc.... 
    public virtual ArmourLookup Lookup {get; set;} 
} 

Créer une sous-classe discriminé mapping défini

public class LookupMap : ClassMap<Lookup> { 
    public LookupMap(){ 
     Id(x=>x.Id).GeneratedBy.Assigned(); //Needs to be a unique ID 
     Map(x=>x.Tablename); 
     Map(x=>x.ColumnName); 
     Map(x=>x.Description); 
     //Business Info property mappings here 
     Table("LookupView") 
     DiscriminateSubClassesOnColumn<string>("ColumnName"); 
     ReadOnly(); 
    } 
} 

public class ArmourLookupMap : SubClassMap<ArmourLookup> { 
    public ArmourLookupMap(){ 
     DiscriminatorValue("ArmourColumn"); 
    } 
} 

Maintenant, vous pouvez répéter la sous-classe de mappage pour chaque colonne que vous avez créer de nouveaux types avec facilité. Le problème ici est que vous ne pouvez pas mettre à jour ou insérer de nouvelles recherches dans la vue, vous êtes donc en mode lecture seule. Cette méthode utilise le nom de colonne comme discriminateur, supprimant ainsi le nom de la table, mais si vous avez des noms de colonne en double dans votre table de recherche, vous pouvez créer une classe de recherche de base pour chaque table et spécifier une condition de filtre dans le mappage.


Une autre solution possible pourrait être d'utiliser les Enums générés par les modèles T4 à partir des tables de recherche. Bien que ce soit aussi une approche en lecture seule.


Vous pouvez également tracer chaque table de consultation en tant que classe et utiliser le modèle de discriminateur pour obtenir différents types de la table ColumnInfo.

public class TableInfo { 
    public virtual int Id {get; set;} 
    public virtual string Tablename {get; set;} 
    public IList<ColumnInfo> Columns {get; set;} 
} 

public class ColumnInfo { 
    public virtual int Id {get; set;} 
    public virtual TableInfo TableInfo {get; set;} 
    public virtual BusinessInfo BusinessInfo {get; set;} 
    public virtual LookupDescriptionInfo LookupDescriptionInfo {get; set;} 
    //Other properties 
} 

public class ArmourInfoColumn : ColumnInfo { 
    //In the mapping you would discriminate on the columnname column. 
} 

etc... 

Encore une fois vous pouvez éventuellement décider de distinguer sur certaines classes XTable si vous avez des noms de colonnes en double dans la table d'information de la colonne, mais différente de tableid.

Vous pouvez également discriminer sur le ColumnType (numérique ou texte) et sous-classer la classe LookupDescription pour utiliser différentes colonnes pour la propriété "Description".

Si vous pouviez fournir votre structure de table et quelques exemples de valeurs, je pourrais vous en donner plus pour vous.

+0

Des trucs géniaux! Je me suis retrouvé avec une légère variation de votre première option. J'ai créé une vue qui utilise

- - comme ID unique et
- comme discriminateur. J'ai une classe abstraite Lookup qui contient les propriétés Id, LookupId et LookupDescription, puis j'ai créé des sous-classes pour chaque entité de recherche individuelle. Chaque recherche a les mêmes colonnes, donc mes classes de recherche concrètes n'ajoutent aucune nouvelle propriété. –

Questions connexes