2009-09-04 4 views
2

Je n'arrive pas à mapper une structure arborescente à l'aide de NHibernate Fluent, sans avoir à mettre dans ce que je crois être un hack.Mappage de l'arborescence avec Fluent NHibernate

Considérons les classes suivantes:

  • Node (résumé, a int Id et GroupNode Parent (si null, le noeud se trouve dans le nœud racine))
  • GroupNode (hérite de Node, a IList<GroupNode> Groups et IList<ItemNode> Items)
  • ItemNode (hérite de Item)

Idéalement, cela aurait la structure de base de données suivante:

  • GroupNodes (entier Id, ParentId entier annulable)
  • ItemNodes (entier Id, ParentId entier annulable)

Mon cartographes ressemble ceci:

public class GroupNodeMap : ClassMap<GroupNode> 
{ 
    public GroupNode() 
    { 
     Id(x => x.Id); 
     References(x => x.Parent); 
     HasMany(x => x.Groups).LazyLoad(); 
     HasMany(x => x.Items).LazyLoad(); 
    } 
} 

public class ItemNodeMap : ClassMap<ItemNode> 
{ 
    public ItemNodeMap() 
    { 
     Id(x => x.Id); 
     References(x => x.Parent); 
    } 
} 

Malheureusement, cela crée un ensemble de références en double (Chaque table reçoit à la fois un ParentId et un GroupNodeId. Je peux modifier ce comportement en ajoutant .KeyColumn("ParentId") après .LazyLoad(), mais cela ressemble à un hack, et je voudrais qu'il s'exprime en utilisant soit des conventions ou des lambdas au lieu d'une chaîne magique.

Quelqu'un pourrait-il me diriger dans la bonne direction?

+0

J'ai le même problème ... – UpTheCreek

+0

avez-vous trouvé une solution pour cela? –

Répondre

-1

NHibernate fluide a des conventions de dénomination. Si vous n'aimez pas utiliser les noms de colonne de base de données (ce n'est pas un hack), vous devez renommer les colonnes de la base de données. Check Available Conventions

0

J'ai exactement le même type de structure dans ma base de données et j'ai également utilisé la méthode KeyColumn. Ce n'est pas vraiment un hack, c'est juste expliquer fluentnhibernate quel est le nom de l'autre côté de la collection.

Ceci est un peu un cas particulier puisque généralement si vous définissez "HasMany (x => x.Groups)", il va chercher "GroupId" dans la table Group. Mais dans votre cas, GroupId est déjà la clé de cette colonne et ce n'est pas la colonne que vous voulez utiliser pour cela. C'est pourquoi vous devez définir "KeyColumn" pour indiquer à fnh quelle colonne il doit utiliser pour la relation.

La méthode KeyColumn est souvent utilisée, en particulier lorsque vous travaillez sur une base de données qui n'a pas été créée pour NHibernate et que les colonnes ont des noms bizarres.

1

Voici un exemple que vous pouvez essayer d'utiliser les conventions Automap et SQLite:

namespace Entities 
{ 
    public abstract class Node 
    { 
     public virtual int Id { get; set; } 
     public virtual GroupNode Parent { get; set; } 
    } 

    public class ItemNode : Node 
    { 
    } 

    public class GroupNode : Node 
    { 
     public virtual IList<GroupNode> Groups { get; set; } 
     public virtual IList<ItemNode> Items { get; set; } 
    } 
} 

class Program 
{ 
    static void Main() 
    { 
     if (File.Exists("data.db3")) 
     { 
      File.Delete("data.db3"); 
     } 

     using (var factory = CreateSessionFactory()) 
     { 
      using (var connection = factory.OpenSession().Connection) 
      { 
       ExecuteQuery("create table GroupNode(Id integer primary key, Parent_Id integer)", connection); 
       ExecuteQuery("create table ItemNode(Id integer primary key, Parent_Id integer)", connection); 

       ExecuteQuery("insert into GroupNode(Id, Parent_Id) values (1, null)", connection); 
       ExecuteQuery("insert into GroupNode(Id, Parent_Id) values (2, 1)", connection); 
       ExecuteQuery("insert into GroupNode(Id, Parent_Id) values (3, 1)", connection); 

       ExecuteQuery("insert into ItemNode(Id, Parent_Id) values (1, 1)", connection); 
       ExecuteQuery("insert into ItemNode(Id, Parent_Id) values (2, 1)", connection); 
      } 

      using (var session = factory.OpenSession()) 
      using (var tx = session.BeginTransaction()) 
      { 
       var node = session.Get<GroupNode>(1); 
       tx.Commit(); 
      } 
     } 
    } 

    private static ISessionFactory CreateSessionFactory() 
    { 
     return Fluently.Configure() 
      .Database(
       SQLiteConfiguration.Standard.UsingFile("data.db3").ShowSql() 
      ) 
      .Mappings(
       m => m.AutoMappings.Add(
        AutoMap 
         .AssemblyOf<Program>() 
         .Where(t => t.Namespace == "Entities") 
       ) 
      ).BuildSessionFactory(); 
    } 

    static void ExecuteQuery(string sql, IDbConnection connection) 
    { 
     using (var command = connection.CreateCommand()) 
     { 
      command.CommandText = sql; 
      command.ExecuteNonQuery(); 
     } 
    } 
} 
+0

Le lien est rompu. –

Questions connexes