2017-09-30 1 views
0

Ich habe ein NHibernate 4-Projekt mit mehreren Auflistungsbeziehungen. Ich teste das Objektmodell in Unit-Tests und trainiere alle Kollektionen. Die meisten funktionieren einwandfrei, aber in einem Fall wird die untergeordnete Sammlung ordnungsgemäß in Kaskade gespeichert, aber beim Laden der übergeordneten Entität und beim Untersuchen der Auflistungseigenschaft ist die untergeordnete Auflistung leer.NHibernate 4 untergeordnete Sammlung gespeichert, aber nicht neu geladen

Hier sind die abgekürzten Klassen. GatewayUser ist das übergeordnete Objekt und enthält eine Sammlung von Student. Die Auflistung verfügt über eine private Sicherungseigenschaft und AddStudent/RemoveStudent-Methoden.

Weitere Komplikationen: Ich verwende die NHibernate.AspNet.Identity-Bibliothek für OAuth2-Benutzerverwaltung und GatewayUser erbt von IdentityUser. Diese wiederum erbt von der internen Basis-Entitätsklasse der Bibliothek, die sich von der eigenen Basisklasse meines Projekts unterscheidet.

public class GatewayUser: IdentityUser { public GatewayUser() { }

public virtual string FirstName { get; set; } 
    // ...More value properties and OAuth stuff omitted 

    // students associated with this user 
    private IList<Student> _students = new List<Student>(); 

    public virtual IList<Student> Students 
    { 
     get { return new ReadOnlyCollection<Student>(_students); } 
    } 

    public virtual GatewayUser AddStudent(Student s) 
    { 
     if (_students.Contains(s)) 
      return this; 

     s.GatewayUser = this; 
     _students.Add(s); 
     return this; 
    } 

    public virtual GatewayUser RemoveStudent(Student s) 
    { 
     if (_students.Contains(s)) 
     { 
      _students.Remove(s); 
     } 
     return this; 
    } 

Schüler ist gewöhnlichere; Es erbt von meiner eigenen BaseEntity-Klasse, hat viele Werteigenschaften und eine eigene Kindsammlung von ProgramApplication-Elementen. Interessanterweise spart und lädt diese Sammlung gut; Es hat dieselbe Struktur (privater Backer usw.) wie die fehlerhafte Sammlung in GatewayUser.

Das Mapping ist kompliziert, weil die Bibliothek ihre Klassen intern mit NHiberante.Mapping.ByCode.Conformist-Klassen abbildet (mit denen ich keine Erfahrung habe). Ich ordne meine eigenen Klassen mit NHibernate automapping, weil ich so viele Klassen und Eigenschaften zuordnen muss. Um alles in Ordnung zu bringen, habe ich die Mapping-Hilfsklasse der Bibliothek kopiert und ein wenig modifiziert, um meine Basis-Entity-Klassen zu ihrer Liste namens baseEntityToIgnore hinzuzufügen. Ich musste auch ein konformes Mapping für GatewayUser erstellen, da es einen anderen Basis-Entitätstyp hat und mein automatisches Zuordnen es nicht aufnehmen würde.

Die Unit-Test sieht wie folgt aus:

[Test] 
    public void GatewayUserCascadesStudents() 
    { 

     var u = new GatewayUser() { FirstName = "Mama", LastName = "Bear", UserName = "[email protected]" }; 
     var s1 = new Student() { FirstName = "First", LastName = "Student" }; 
     var s2 = new Student() { FirstName = "Second", LastName = "Student" }; 

     u.AddStudent(s1).AddStudent(s2); 

     using (var s = NewSession()) 
     using (var tx = s.BeginTransaction()) 
     { 
      s.Save(u); 
      tx.Commit(); 
     } 

     GatewayUser fetched = null; 
     int count = 0; 
     using (var s = NewSession()) 
     { 
      fetched = s.Get<GatewayUser>(u.Id); 
      count = fetched.Students.Count; 
     } 

     Assert.AreEqual(2, count); 
    } 

Die erzeugte SQL in beide AspNetUsers und GatewayUser Einsätze (die die Vererbungsbeziehung) und fügt zwei Datensätze in Studenten. Alles gut. Beim Abrufen verbindet SELECT die beiden Benutzertabellen und ich erhalte ein GatewayUser-Objekt, aber der Zugriff auf die Student-Sammlung löst keinen SELECT für die Student-Tabelle aus. Aber wenn ich das Mapping zu Lazy (CollectionLazy.NoLazy) ändere, erscheint das SQL, um Schüler mit Interesse zu laden, im Protokoll, aber die Sammlung ist nicht gefüllt. Wenn ich die Datenbank von SQLite auf Sql Server umschalte, sehe ich die Studentenakten in der Tabelle. Das generierte SQL (wenn NoLazy angewendet wird) wird sie abrufen. Also am Ende der Datenbank sieht es gut aus.

Ich muss denken, meine Frankenstein Mapping-Situation ist schuld. Ich mische das konforme Mapping der Bibliothek mit Fluent Mapping, und es gibt zwei verschiedene Basis-Entity-Klassen. Das generierte Schema sieht jedoch korrekt aus und die Speicherkaskaden sind korrekt. Daher weiß ich nicht, ob das der Fall ist.

Antwort

0

Ich habe meine eigene Antwort gefunden. Meine Abbildung von der Liste der übergeordneten Klasse war wie folgt aus:

public class GatewayUserMap: JoinedSubclassMapping { public GatewayUserMap() { Key (g => g.Column ("Id")); Eigenschaft (c => c.FirstName, m => m.Length (50)); // ...mehr Eigenschaften

 List(gu => gu.Students, map => 
     { 
      map.Key(c => c.Column("GatewayUser_Id")); 
      map.Cascade(Cascade.All | Cascade.DeleteOrphans); 
      map.Index(li => li.Column("ListIndex")); 
      map.Access(Accessor.Field | Accessor.NoSetter); 
     } 
     ); 
    } 
} 

Ich habe ein privates Unterstützungsfeld für die Sammlung. Das Entfernen von Accessor.NoSetter aus der Auflistungszuordnung hat es behoben. In der Tat, es funktionierte immer noch ohne Accessor.Field - Ich denke, der Mapper macht einen guten Job der Suche nach einem, und die Verwendung, wenn gefunden. Wenn der Name des privaten Backers von "_students" in "funnyName" geändert wurde, konnte der Mapper den Namen nicht finden.

Verwandte Themen