6

Wir haben eine Legacy-Datenbank, die wir nicht ändern können. Und wir versuchen, in den NHibernate statt der alten DataAccess-Ebene zu wechseln, was ein Müll ist und zu langsam ist.NHibernate-Navigatoren, die dem Teil eines zusammengesetzten Schlüsselproblems zugeordnet sind - Legacy-Datenbankverwendung

hat es Tabellen wie diese:

GPI Tabelle hat (PU_ID, PAR_ID, Daten, Data2) Spalten
BLOCK Tabelle hat (GA_ID, Daten, PAR_ID) Spalten
COMPANY Tabelle hat (PU_ID, Data) Spalten

ich diese Zuordnungen für die obigen Tabellen erstellt hatte:

GPI

<class name="GroupPartnerInterest" table="[GPI]"> 
    <composite-id > 
     <key-property name="GroupId" column="PAR_ID" /> 
     <key-property name="CompanyId" column="PU_ID" /> 
    </composite-id> 
    <property name="data" column="Data"/> 
    <property name="data2" column="Data2"/> 
    <many-to-one name="Company" fetch="select" cascade="none"> 
     <column name="PU_ID"/> 
    </many-to-one> 
    <set name="Blocks" cascade="none" inverse="true" fetch="select"> 
     <key property-ref="GroupId"> 
      <column name="PAR_ID"/> 
     </key> 
     <one-to-many class="Block"/> 
    </set> 
</class> 

BLOCK

<class name="Block" table="[BLOCK]" > 
    <id name="BlockId" column="GA_ID" > 
     <generator class="assigned"/> 
    </id> 
    <property name="data" column="Data"/> 
    <property name="GroupId" column="PAR_ID"/> 
    <set name="GroupPartnerInterests" cascade="all-delete-orphan" fetch="select"> 
     <key property-ref="GroupId"> 
      <column name="PAR_ID"/> 
     </key> 
     <one-to-many class="GroupPartnerInterest"/> 
    </set> 
</class> 

UNTERNEHMEN

<class name="Company" table="[COMPANY]"> 
    <id name="CompanyId" column="PU_ID"> 
     <generator class="assigned"/> 
    </id> 
    <property name="data" column="Data"/> 
    <set name="GroupPartnerInterests" cascade="none" inverse="true" fetch="select"> 
     <key> 
      <column name="PU_ID"/> 
     </key> 
     <one-to-many class="GroupPartnerInterest"/> 
    </set> 
</class> 

Die Klassen sind sehr einfach und schlicht. Alle implementieren Equals und GetHashCode-Methoden.

Hier ist die Liste der Navigatoren, die funktionieren:

  • GroupPartnerInterest.Company - hervorragend
  • Company.GroupPartnerInterests - hervorragend
  • GroupPartnerInterest.Company - hervorragend

Und Diese zwei Fehler:

  • Block.GroupPartnerInterests:

ich einen Komponententest haben:

[TestMethod] 
public void TestGroupPartnerInterests() 
{ 
    using (ISession session = SessionFactory.OpenSession()) 
    { 
     IList<Block> blocks = session.CreateCriteria(typeof(Block)) 
      .SetMaxResults(5).List<Block>(); 

     foreach (var block in blocks) 
     { 
      TestContext.WriteLine("Block #{0}", block.BlockId); 

      if (block.GroupPartnerInterests != null) 
      { 
       foreach (GroupPartnerInterest gpi in block.GroupPartnerInterests) 
       { 
        TestContext.WriteLine("Company '{0}':", gpi.Company.CompanyId); 
       } 
      } 
     } 
    } 
} 

Wenn ich Blöcke Navigation Mapping in GPI-Mapping Test funktioniert Kommentar aus und gibt einige Daten:

Block #1
Company 'LALA':
Company 'LALA SA':
Block #2
Company 'BG PO':
Company 'LIMPOPO':
Block #3
Company 'HAHA':
Company 'Other partner(s)':
Block #4

Aber Der Test schlägt mit dem folgenden Fehler fehl:

NHibernate.LazyInitializationException: Initializing[Model.EntityClasses.Block#999]-failed to lazily initialize a collection of role: Model.EntityClasses.Block.GroupPartnerInterests, no session or session was closed.

Die '999' ist vorhanden PAR_ID - Daten sind konsistent: Es gibt zwei Blöcke mit dieser PAR_ID und ein paar Datensätze in GPI.

Warum schließt die Sitzung irgendwann?

  • GroupPartnerInterest.Blocks:

Der Unit-Test ist fast das gleiche wie ich oben erwähnt, sind nur verschiedene Eigenschaften verwendet. Ein Fehler ist unten:

NHibernate.MappingException: NHibernate.MappingException: property not found: GroupId on entity Model.EntityClasses.GroupPartnerInterest.

Wenn ich "Immobilien-ref = GroupId" aus dem Elemente des Block Navigator in dem GPI-Mapping zu entfernen, werde ich die folgende Ausnahme erhalten:

NHibernate.FKUnmatchingColumnsException: NHibernate.FKUnmatchingColumnsException: Foreign key (FKA3966498349694F:[BLOCK] [PAR_ID])) must have same number of columns as the referenced primary key ([GPI] [PAR_ID, PU_ID]).

Ist Gibt es eine Möglichkeit, Blöcke zu GPI zuzuordnen, so dass der GroupPartnerInterest.Blocks Navigator funktioniert?

Danke, Alex

Antwort

2

Das Problem ist folgendes:

  • Wenn Sie eine Einheit mit einem Composite- id haben, müssen alle Verweise auf sie die zusammengesetzte ID halten, so dass es müssen zwei Fremdschlüssel sein.
  • Blöcke in GroupPartnerInterest ist ein Satz, so dass der Fremdschlüssel in Blocks ist und auf GroupPartnerInterest zeigt. Es würde zwei Fremdschlüssel benötigen, die nicht verfügbar sind.
  • property-ref ist der Primärschlüssel durch eine andere Eigenschaft zu ersetzen. Es ist daher eine Eigenschaft der Tabelle auf der einen Seite der Beziehung, die GroupPartnerInterest ist, aber es gibt keine GroupId.
  • Sie könnte wahrscheinlich property-ref für GroupPartnerInterest.Blocks verwenden (da die beiden Fremdschlüssel fehlen, Block.PAR_ID Punkt GPI.PAR_ID zu machen), aber ich würde zweimal darüber nachdenken.

Ich kann Ihnen hier keine funktionierende Lösung geben. Ich verwende keine zusammengesetzten Schlüssel und das ist komplexer. Aber es gibt noch ein paar Gedanken:

  • Ich würde versuchen, den zusammengesetzten Schlüssel zu vermeiden. Wenn dies nicht möglich ist, schreiben Sie eine Klasse, die den zusammengesetzten Schlüssel darstellt. Dies macht es viel einfacher, damit umzugehen.
  • Ich würde versuchen, Beziehungen zu vermeiden, die nicht auf dem Primärschlüssel basieren. Es kann Gründe geben, etwas anderes zu tun, NH unterstützt sie, ich denke nur, dass sie Probleme verursachen.

Warum wird die Sitzung geschlossen? Ich weiß nicht, ich würde mir die Stack-Spur ansehen. Wird die Ausnahme wirklich aus dem using-Block geworfen? Oder wird es von einer TestCleanup Methode geworfen?

+0

Vielen Dank für die eingehende Antwort! Ich werde versuchen, unser Team davon zu überzeugen, DB-Schema nur ein wenig zu ändern: fügen Sie einen automatisch generierten (inkrementellen) Primärschlüssel zur GPI-Tabelle hinzu. Dies wird behoben Eigentum-Ref = GroupId Problem und sollte meine Problem Navigationseigenschaften beheben – LucID

+0

Ich habe ein sehr ähnliches Problem. Ich habe versucht, dieses Szenario sowohl mit XML als auch mit flüssigen Zuordnungen abzubilden, aber keine Freude. Leider kann ich das Schema zu diesem Zeitpunkt nicht ändern. Kann ich dich dazu bringen, einen Blick darauf zu werfen? http://stackoverflow.com/questions/25191275/fluent-nhibernate-map-hasmany-to-entity-table-with-no-primary-key –