4

J'ai besoin d'un mappage NHibernate fluide qui remplira les conditions suivantes (si rien d'autre, je prendrai également le mappeur XML NHibernate approprié et le reverse engineering il).Fluid NHibernate: mappage complexe many-to-many (avec des colonnes supplémentaires) et réglage de l'extraction


DÉTAILS

J'ai plusieurs à plusieurs entre deux entités: Parent et Child. Cela est accompli par une table supplémentaire pour stocker les identités du Parent et de l'Enfant. Cependant, j'ai également besoin de définir deux colonnes supplémentaires sur ce mapping qui fournissent plus d'informations sur la relation.

C'est à peu près comment j'ai défini mes types, au moins les parties concernées (où Entity un certain type de base qui fournit une propriété Id et vérifie l'équivalence sur cette base Id):

public class Parent : Entity 
{ 
    public virtual IList<ParentChildRelationship> Children { get; protected set; } 

    public virtual void AddChildRelationship(Child child, int customerId) 
    { 
     var relationship = new ParentChildRelationship 
         { 
          CustomerId = customerId, 
          Parent = this, 
          Child = child 
         }; 
     if (Children == null) Children = new List<ParentChildRelationship>(); 
     if (Children.Contains(relationship)) return; 
     relationship.Sequence = Children.Count; 
     Children.Add(relationship); 
    } 
} 

public class Child : Entity 
{ 
    // child doesn't care about its relationships 
} 

public class ParentChildRelationship 
{ 
    public int CustomerId { get; set; } 
    public Parent Parent { get; set; } 
    public Child Child { get; set; } 
    public int Sequence { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) return false; 
     if (ReferenceEquals(this, obj)) return true; 
     var other = obj as ParentChildRelationship; 
     if (return other == null) return false; 

     return (CustomerId == other.CustomerId 
      && Parent == other.Parent 
      && Child == other.Child); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      int result = CustomerId; 
      result = Parent == null ? 0 : (result*397)^Parent.GetHashCode(); 
      result = Child == null ? 0 : (result*397)^Child.GetHashCode(); 
      return result; 
     } 
    } 
} 

Le les tables de la base de données ressemblent approximativement (prendre les clés primaires/étrangères et pardonner la syntaxe):

create table Parent (
    id int identity(1,1) not null 
) 

create table Child (
    id int identity(1,1) not null 
) 

create table ParentChildRelationship (
    customerId int not null, 
    parent_id int not null, 
    child_id int not null, 
    sequence int not null 
) 

Je suis OK avec Parent.Children étant une propriété chargée paresseux. Cependant, ParentChildRelationship devrait charger ardemment ParentChildRelationship.Child. En outre, je veux utiliser une jointure lorsque j'ai hâte de charger.

SQL, lors de l'accès Parent.Children, NHibernate devrait générer une requête équivalente à:

SELECT * FROM ParentChildRelationship rel LEFT OUTER JOIN Child ch ON rel.child_id = ch.id WHERE parent_id = ?

OK, donc à faire que j'ai applications qui ressemblent à ceci:

ParentMap : ClassMap<Parent> 
{ 
    public ParentMap() 
    { 
     Table("Parent"); 
     Id(c => c.Id).GeneratedBy.Identity(); 
     HasMany(c => c.Children).KeyColumn("parent_id"); 
    } 
} 

ChildMap : ClassMap<Child> 
{ 
    public ChildMap() 
    { 
     Table("Child"); 
     Id(c => c.Id).GeneratedBy.Identity(); 
    } 
} 


ParentChildRelationshipMap : ClassMap<ParentChildRelationship> 
{ 
    public ParentChildRelationshipMap() 
    { 
     Table("ParentChildRelationship"); 
     CompositeId() 
       .KeyProperty(c => c.CustomerId, "customerId") 
       .KeyReference(c => c.Parent, "parent_id") 
       .KeyReference(c => c.Child, "child_id"); 
     Map(c => c.Sequence).Not.Nullable(); 
    } 
} 

Donc, dans mon test si j'essaie d'obtenir myParentRepo.Get(1).Children, cela m'apporte en fait toutes les relations et, quand j'y accède à partir de la relation, les objets Enfant (par exemple, je peux les saisir tous en faisant parent.Children.Select(r => r.Child).ToList()). Cependant, le code SQL généré par NHibernate est inefficace. Lorsque j'accède à parent.Children, NHIbernate fait un SELECT * FROM ParentChildRelationship WHERE parent_id = 1 puis un SELECT * FROM Child WHERE id = ? pour chaque enfant dans chaque relation. Je comprends pourquoi NHibernate le fait, mais je n'arrive pas à comprendre comment configurer le mappage pour que NHibernate soit interrogé comme je l'ai mentionné plus haut.

Répondre

2

Je ne comprends pas pourquoi cela ne fonctionne pas comme vous le faites, mais je peux vous dire comment je mapper:

<class name="Parent"> 

    <id .../> 

    <list name="Children" table="ParentChildRelationship"> 
     <key column="parent_id"/> 
     <index column="Sequence"/> 

     <composite-element> 
      <property name="CustomerId"/> 
      <many-to-one name="Child"/> 
     </composite-element> 
    </list> 

</class> 

<class name="Child"> 
    <id .../> 
    <property .../> 
</class> 

Pour améliorer les performances, essayez de le faire chercher les nombreux -to-one par une jointure:

 <many-to-one name="Child" fetch="join" /> 
+0

Je suis impatient de comparer mes mappings avec les vôtres et voir si je peux obtenir ce travail. Je vous le ferai savoir dès que je pourrai y arriver. Merci! – HackedByChinese

+0

+1 pour une belle cartographie. Je n'aurais pas pensé à le faire de cette façon en utilisant 'composite-element'. –

Questions connexes