2010-06-30 3 views
4

J'utilise FluentNHibernate. Je n'utilise pas la cartographie automatique. J'ai une classe de base qui est sous-classée. Lorsque j'interroge la classe de base, elle effectue une requête supplémentaire sur la sous-classe. Voici la (pièce) exemple de ce que je fais:NHibernate et l'héritage créant un comportement de double requête inattendue?

public class Foo 
{ 
    int Id; 
    string SomeValue; 
} 

je crée une autre classe qui représente un dossier d'audit de la première et je posséderai:

public class FooAudit : Foo 
{ 
    DateTime DateModified; 
} 

Je crée les correspondances distinctes pour chaque qui vont à leurs propres tables:

public class FooMap : ClassMap<Foo> 
{ 
    public FooAuditMap() 
    { 
     Table("Foo"); 
     Id(x => x.Id).Column("FOO_ID"); 
     Map(x => x.SomeValue).Column("SOME_VALUE"); 
    } 
} 

public class FooAuditMap : ClassMap<FooAuditMap> 
{ 
    public FooAuditMap() 
    { 
     Table("FooAudit"); 
     CompositeId() 
      .KeyProperty(x => x.DateModified, c => c.ColumnName("AUDIT_DATE")); 
      .KeyProperty(x => x.Id, c => c.ColumnName("FOO_ID")); 
     Map(x => x.SomeValue).Column("SOME_VALUE"); 
    } 
} 

j'effectue une requête sur Foo:

public virtual IEnumerable<Foo> List() 
{ 
    using (var session = SessionFactory.OpenSession()) 
    { 
     return session.CreateCriteria<Foo>().List<Foo>(); 
    } 
} 

Qui frappe ensuite la base de données deux fois, une fois pour exécuter cette requête sur Foo et à nouveau sur FooAudit.

Pourquoi fait-il deux requêtes? J'ai généré les fichiers HBM et il n'y a absolument rien liant ces classes.

EDIT: Pour être complet, voici à quoi ressemble la configuration bootstrap.

public static ISessionFactory CreateSessionFactory() 
{ 
    return Fluently 
     .Configure() 
     .Database 
     (
      FluentNHibernate.Cfg 
      .Db.MsSqlConfiguration.MsSql2005 
      .ConnectionString(GetConnectionString()) 
     ) 
     .Mappings(m => m 
      .FluentMappings.AddFromAssemblyOf<Foo>() 
      .Conventions.Add(typeof(EnumConvention))) 
     .BuildSessionFactory(); 
} 

Répondre

4

Ce que vous voyez est le comportement attendu.

L'interrogation d'une classe de base interroge également les classes héritées.

S'il existe un mappage NHibernate explicite pour cela (sous-classe, joint-sous-classe, etc.), ce sera juste une requête. Dans le cas contraire, il est considéré comme une définition implicitement polymorphe, et deux requêtes sont émises pour renvoyer des résultats de tous.

Je crois (des docs, je n'ai pas essayé) que vous pouvez éviter cela en mappant la classe avec polymorphism="explicit". Je ne sais pas si Fluent le supporte.

+0

Génial, merci! –

0

Essayez:

public class FooAuditMap : SubclassMap<FooAudit> 
{ 
    public FooAuditMap() 
    { 
     Table("FooAudit"); 
     CompositeId() 
      .KeyProperty(x => x.DateModified, c => c.ColumnName("AUDIT_DATE")); 
      .KeyProperty(x => x.Id, c => c.ColumnName("FOO_ID")); 
     Map(x => x.SomeValue).Column("SOME_VALUE"); 
    } 
} 

Vous avez encore un problème parce que l'identifiant de Foo et FooAudit sont différents. Si FooAudit est une sous-classe de Foo, il devrait avoir le même identifiant stocké dans la table Foo.

Mise à jour basée sur le commentaire OP: Vous pouvez certainement avoir une chaîne d'héritage dans le modèle de domaine sans l'exprimer dans NHibnerate. Changez juste le FooAuditMap pour hériter ClassMap<FooAudit>. Cependant, votre requête pour l'objet de type Foo n'inclura aucun type FooAudit car NH ne connaît pas la relation.

Mais je pense que ce que vous avez ici est une relation un-à-plusieurs - Foo a une collection de FooAudits - et vous devez le mapper de cette façon.

Mise à jour 2: Il semble que ma déclaration précédente "Cependant votre requête pour l'objet de type Foo n'inclura aucun type FooAudit parce que NH ne connaît pas la relation." est faux. Il existe un moyen de renvoyer uniquement la classe de base en limitant les résultats en utilisant le special class property mais ce n'est pas une excellente solution.

Je pense que vous feriez mieux de vous débarrasser de l'héritage et que les deux classes implémentent une interface ou mappent les propriétés communes en tant que composant.

+0

Je suis peut-être en train de faire quelque chose qui n'est pas naturel à NHibernate. Pensez à Foo et FooAudit comme deux choses complètement séparées. Il arrive que l'un dérive de l'autre pour réutiliser certaines propriétés. Je veux profiter de la réutilisation sans faire croire à NHibernate que j'ai besoin d'associer les mappages pour une raison quelconque. Cela ne semble pas possible. –

+0

J'ai mis à jour ma réponse, j'espère que cela aidera. –

+0

Ah, j'ai fait une erreur copier/coller. Je l'ai réparé. J'ai exactement ce que vous avez suggéré. FooAuditMap hérite de ClassMap . Quand j'ai FooAuditMap alors il crée le comportement de double requête que j'ai décrit ci-dessus. Quand je l'enlève, ça s'en va. Il n'y a pas de connexion entre les objets dans la config ou le mapping mais l'interrogation de Foo crée les deux requêtes. –

Questions connexes