2009-07-19 13 views
1

Comment puis-je laisser NHibernate ignorer les propriétés supplémentaires d'une sous-classe de mon modèle?Pas de persister pour ... {SUBCLASS} NHibernate avec NHibernate fluide

class SuperModel { // hot I know 
{ 
    public Guid Id { get; private set; } 
    public string FirstName { get; set; } 
} 

class SubModel : SuperModel { 
    public string FavoriteColor { get; set; } 
} 

Je veux vraiment que pour stocker les données SuperModel utilisant mon référentiel et le FavoriteColor ailleurs, mais je reçois

No persister for: SubModel 

même si je l'enregistrer avec mon dépôt comme

void Store(SuperModel model) { 
    using (var session = Session){ 
     session.SaveOrUpdate(model); // <<<< The exception is thrown here 
    } 
} 

et d'autres où j'utilise

void WhatToDo(SubModel model) { 
    doSomething(model.FavoriteColor); 
} 

Et je l'utilise en tant que telle

var model = new SubModel { FirstName = "Miranda", FavoriteColor = "Green" }; 
modelRepository.Store(model); 
someService.WhatToDo(model); 

Quelqu'un sait comment je peux couramment configurer cela? Merci.

FYI- le moulage implicite et explicite n'a aucun effet.

Modifier

Mes correspondances sont comme ça

class SuperModelMap : ClassMap<SuperModel> 
{ 
    public SuperModelMap() 
    { 
     WithTable("SuperModels"); 
     Id(x => x.Id); 
     Map(x => x.FirstName); 
    } 
} 

Edit 2

je figure/découvert que je pouvais le faire, mais dans ma base de données, je dois avoir une table fictive, ce qui serait inefficace. Il fonctionne, mais il doit y avoir une meilleure façon ...

Dans mon SuperModelMap ...

JoinedSubClass<SubModel>("SubModel", MapSubModel); 

private void MapSubModel(JoinedSubClassPart<SubModel> part) 
{ 
    // Leave this empty 
} 

Edit 3 Je suis plus proche, mais je reçois encore une autre erreur sur la sélection.

J'ai essayé ceci.

DiscriminateSubClassesOnColumn("Id") 
    .SubClass<SubModel>(m => { }); 

InnerException { "objet avec id: 5586b075-47f1-49c8-871c-9c4d013f7220 n'a pas été de la sous-classe spécifiée: SuperUser (discriminateur était: '1000')"} System.Exception {} NHibernate.WrongClassException

+0

Pouvez-vous nous montrer vos correspondances peut-être? –

+0

J'ai essayé de résoudre mon problème. oui après le commentaire de "hot je sais" pour tout le reste de la page je viens de lire le code comme une histoire et ne pouvait pas arrêter de rire. Bon cas de test solide pour l'apprentissage :) – percent20

+0

@ percent20 - votez-le alors! –

Répondre

1

NHibernate suppose que vous souhaitez récupérer exactement le même objet que vous persistez. Ainsi, même si vous ne vous souciez pas des propriétés supplémentaires, vous pouvez vous intéresser au type d'objet. Si ce n'est pas le cas, la solution la plus simple consisterait à créer une copie superficielle de l'objet SubModel, mais au lieu de créer un objet SubModel, créez un objet SuperModel. Je suppose que vous avez réfléchi à ce sujet et que vous ne l'avez pas aimé.Si vous souhaitez éviter la table factice, mais peut vivre avec la colonne factice, je vous suggère d'appeler:

DiscriminateSubClassesOnColumn("dummycolumn") 
.SubClass<SubModel>(m => { }); 

Cette colonne sera utilisée par NHibernate pour stocker des informations sur le type d'objet persistait. Lorsque vous chargez un objet à partir de la base de données, ce sera SubModel ou SuperModel, en fonction de ce que c'était lorsque vous l'avez persisté.

Votre solution avec l'appel de DiscriminateSubClassesOnColumn n'a pas fonctionné, car NHibernate n'a pas pu déterminer quelle classe utiliser en fonction de la colonne id.

Une autre idée: Je ne sais pas si cela fonctionnera, mais vous pouvez ajouter un autre mapping, pour SubModel, exactement le même que pour SuperModel. Ensuite, NHibernate devrait conserver SubModel dans la même table que SuperModel, et quand vous demandez votre objet, il devrait récupérer l'objet SuperModel. Malheureusement, je ne peux pas tester cette solution maintenant, peut-être que vous pouvez la faire fonctionner. Pas de sous-classe dans cette solution - deux mappages "parallèles".

+0

Il n'a pas aimé quand j'ai essayé de récupérer. –

+0

D'accord, je l'ai eu à travailler, mais maintenant il renvoie un sous-modèle. Un moyen d'arrêter ça? –

+0

Votre idée est valide, mais elle ne serait pas réutilisable. –

4

Vous pouvez affiner cette solution pour la rendre plus réutilisable. Si je comprends bien, vous n'aimez pas la duplication de cartographie. Cela peut être évité:

J'ai créé une classe SuperModelMapHelper qui contient une méthode d'extension:

public static class SuperModelMapHelper 
{ 
    public static void MapSuperModel<T>(this ClassMap<T> classMap) 
     where T : SuperModel 
    { 
     classMap.WithTable("SuperModels"); 
     classMap.Id(x => x.Id); 
     classMap.Map(x => x.FirstName); 
    } 
} 

Comme vous pouvez le voir - il est générique et acceptera l'une des sous-classes de supermodel. Ensuite, il y a deux applications:

public class SuperModelMap : ClassMap<SuperModel> 
{ 
    public SuperModelMap() 
    { 
     MapSuperModel(); 
    } 
} 

public class SubModelMap : ClassMap<SubModel> 
{ 
    public SubModelMap() 
    { 
     MapSuperModel(); 
    } 
} 

Je l'ai utilisé la méthode d'extension pour préserver la convention de FluentNHibernate, vous pouvez le rendre simple méthode statique et passer carte de classe en tant que paramètre.

Et ce code:

Guid id; 
using (var session = sf.OpenSession()) 
using (var transaction = session.BeginTransaction()) 
{ 
    var subModel = new SubModel() 
         {FavoriteColor = "blue", FirstName = "Jane"}; 
    session.Save(subModel); 
    id = subModel.Id; 
    transaction.Commit(); 
} 

using (var session = sf.OpenSession()) 
using (var transaction = session.BeginTransaction()) 
{ 
    var superModel = session.Get<SuperModel>(id); 
    Console.WriteLine(superModel.GetType().Name); 
    Console.WriteLine(superModel.FirstName); 
    transaction.Commit(); 
} 

fonctionne comme prévu - le type est superclasse. Notez que j'ai créé une deuxième session. Vous devez vider votre session avant d'essayer de charger l'entité dans la même session que vous l'avez enregistrée, car NHibernate diffère l'exécution de la requête.

En utilisant cette solution, il y a très peu de duplication. Vous pouvez étudier la fonctionnalité AutoMapping de FluentNHibernate pour le réduire encore plus - peut-être que créer une convention propre vous permettrait de mapper automatiquement ces classes.

Questions connexes