2012-03-31 7 views
2

Ich habe zwei Klassen, Benutzer- und Rollen, definiert als:NHibvernate 3.2 viele zu viele bevölkern nicht Tisch beitreten

public class User : Entity 
{ 
    // other properties ... 
    public virtual string Username 
    public virtual ICollection<Role> Roles { get; set; } 
} 

public class Role : Entity 
{ 
    public virtual string Name { get; set; } 
    public virtual ICollection<User> Users { get; set; } 
} 

In meinem Mapping-Code, habe ich die folgenden:

mapper.Class<User>(map => 
{ 
    map.Bag(x=>x.Roles, 
     cm=> 
     { 
      cm.Table("UserRole"); 
      cm.Cascade(Cascade.All); 
      cm.Key(k => k.Column("[User]")); 
     }, 
     em=> 
     { 
      em.ManyToMany(mm => 
      { 
       mm.Column("[Role]"); 
      }); 
     }); 

}); 

mapper.Class<Role>(map => 
{ 
    map.Bag(x=>x.Users, 
     cm=> 
     { 
      cm.Inverse(true); 
      cm.Table("UserRole");       
      cm.Key(k=>k.Column("[Role]")); 
     }, 
     em => 
     { 
      em.ManyToMany(mm => 
      { 
       mm.Column("[User]"); 
      }); 
     }); 
}); 

Die Zuordnungen Generieren Sie das erwartete Schema, aber die Join-Tabelle wird nie ausgefüllt. Das Hinzufügen eines neuen Benutzers mit einer neuen Rolle in seiner Sammlung behält die Rolle und dann den Benutzer für die entsprechenden Tabellen bei, aber die Join-Tabelle bleibt leer. Warum?

Edit: Ich habe noch keinen Fortschritt in diesem Bereich gemacht. Ich bin absolut sicher, dass das Mapping korrekt ist und das korrekte Schema generiert wird, aber die Join-Tabelle ist einfach nicht gefüllt. Zu Testzwecken mir generierenden Einheiten NBuilder mit etwa so:

var roles = new Role[] 
{ 
    new Role("Admin"), 
    new Role("Manager"), 
    new Role("User") 
}; 

var users = Builder<User>.CreateListOfSize(10) 
    .TheFirst(1) 
     .Do(x => 
      { 
       x.Roles.Add(roles[0]); 
       x.Roles.Add(roles[1]); 
       roles[0].Users.Add(x); 
       roles[1].Users.Add(x); 
      }) 
    .All() 
     .With(x => x.Id = 0) 
     .And(x => x.Version = 0) 
     .And(x => x.Username = "test user") 
     .And(x => x.Password = "test password") 
     .Do(x => 
     { 
      x.Roles.Add(roles[2]); 
      roles[2].Users.Add(x); 
     } 
    .Build(); 


foreach (var u in users) session.Save(u); 

Die Benutzer- und Rolleneinheiten korrekt beibehalten werden, aber die Join-Tabelle bleibt leer. Das bedeutet, dass ich die Rollen für einen bestimmten Benutzer später nicht effektiv abfragen kann, wodurch der Punkt ungültig wird.

Antwort

0

Am Ende habe ich die NHibernate-Quelle heruntergeladen und direkt darauf verwiesen, damit ich sie durchgehen konnte. Es stellte sich heraus, dass es etwas damit zu tun hatte, dass mein Code zum Generieren der Testdaten nicht in eine explizite Sitzungstransaktion verpackt war. Sobald ich das hinzugefügt habe, war es in Ordnung. Ich würde gerne eine Erklärung dazu sehen, da ich dem Code nicht ganz klar folgen konnte, aber ich bin zumindest überzeugt, dass das Problem gelöst ist.

+0

Großartig, dass Sie das herausgefunden haben! –

+0

Auch ich denke, dass Sitzung.Flush(); Nach dem Speichern sollte auch funktionieren (ohne explizite Transaktion). Benutzer und Rolle werden ohne Notwendigkeit einer Transaktion gespeichert, da NH eine Rückmeldung von der Datenbank erhalten muss (wie automatisch generierte IDs), nachdem NH Datensätze in der Kreuztabelle speichern kann. –

+0

Versuchen Sie nicht, dieses Verhalten zu umgehen, indem Sie Flush verwenden. nhibernate wurde entwickelt, um explizite Transformationen zu verwenden, also möchten Sie das akzeptieren. Siehe z.B. Die NHProf Dokumentation: http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions –

1

Stellen Sie sicher, dass sich beide Klassen gegenseitig referenzieren.

Ich denke, dass Code, ähnlich einen unten, sollte für Sie arbeitet:

role.Users.Add(user);  
user.Roles.Add(role); 

session.Save(user); // NH only saves user and role, so it can get auto-generated identity fields 
session.Flush(); // NH now can save into cross-ref table, because it knows required information (Flush is also called inside of Transaction.Commit()) 

ich ein good answer auf eine Frage über many-to-many mit vielen Erklärungen und Zitaten aus NH-Dokumentation. Ich denke es lohnt sich, es zu lesen.

[EDIT]

In Antwort auf this somewhat similar Frage wird diskutiert, in denen eine explizite Transaktion müssen in Quer Tabelle speichern erwähnt wird.

Ich habe auch Code oben mit dem Hinzufügen session.Flush() bearbeitet, um meine Ergebnisse widerzuspiegeln.