简体   繁体   中英

NHiberate Joined Subclass Invalid Property

I'm trying to work through this issue where the subclass contains a set of properties however two of the properties do not exist in the referenced table.

These two properties exist in an Extension table that has FKs back to the base table. I'm unsure how to modify this xml to support the first joined subclass and addition of another join for the Extension table.

I tried to simply add another joined-subclass for the Extension table, however since the class name was the same, the mapping were invalid.

    <joined-subclass name="SESProgramAssociationAggregate.SESProgramAssociation" table="SESProgramAssociation" lazy="false">
  <key>
    <column name="BeginDate" />
    <column name="EOId" />
    <column name="PEOrganizationId" />
    <column name="ProgramName" />
    <column name="ProgramTypeId" />
    <column name="UDI" />
  </key>

  <!-- PK properties -->
  <property name="UDI" column="UDI" type="int" not-null="true" insert="false" />
  <property name="ProgramTypeId" column="ProgramTypeId" type="int" not-null="true" insert="false" />
  <property name="PEOrganizationId" column="PEOrganizationId" type="int" not-null="true" insert="false" />
  <property name="BeginDate" column="BeginDate" type="date" not-null="true" insert="false" />
  <property name="ProgramName" column="ProgramName" type="string" length="60" not-null="true" insert="false" />
  <property name="EOId" column="EOId" type="int" not-null="true" insert="false" />

  <!-- Properties -->
  <property name="Eligibility" column="Eligibility" type="bool" />
  <property name="SESDescriptorId" column="SESDescriptorId" type="int" not-null="true" />
  <property name="SEHoursPerWeek" column="SEHoursPerWeek" type="decimal" />
  <property name="HoursPerWeek" column="HoursPerWeek" type="decimal" />
  <property name="MultiplyD" column="MultiplyD" type="bool" />
  <property name="MFragile" column="MFragile" type="bool" />
  <property name="LastEvalDate" column="LastEvalDate" type="date" />
  <property name="ReviewDate" column="ReviewDate" type="date" />
  <property name="BeginDate" column="BeginDate" type="date" />
  <property name="EndDate" column="EndDate" type="date" />
  <property name="EventCode" column="EventCode" type="int" />
  <property name="WrittenConsentDate" column="WrittenConsentDate" type="date" />

</joined-subclass>

The final query that is generated fails because it attempts to reference the EventCode and WrittenConsentDate from the SESProgramAssociation table where they do not exist. They actually exist in the Extension table.

I'm not sure how to modify this xml to point those fields to the Extension table so the generated query actually pulls them from that table instead of the wrong one. Any help is greatly appreciated, this is my first experience with NHiberate and needless to say, it's not been fun!

After advice from Frédéric, I updated but got this error:

An exception of type 'NHibernate.MappingException' occurred in NHibernate.dll but was not handled in user code

Additional information: EdFi.Ods.Entities.NHibernate.Mappings.SqlServer.StudentProgramAssociationBase.hbm.xml(79,8): XML validation error: The element 'joined-subclass' in namespace 'urn:nhibernate-mapping-2.2' has invalid child element 'join' in namespace 'urn:nhibernate-mapping-2.2'. List of possible elements expected: 'property, many-to-one, one-to-one, component, dynamic-component, properties, any, map, set, list, bag, idbag, array, primitive-array, joined-subclass, loader, sql-insert, sql-update, sql-delete, resultset, query, sql-query' in namespace 'urn:nhibernate-mapping-2.2'.

Your second table should not be mapped as another joined-subclass , since it does not match a subclass in your domain model.

It should be mapped either as a standalone Extension entity, with the extended entity referencing it as a one-to-one related entity.

Or you can use the join mapping for having a single entity in your domain model. But the join mapping is not allowed on subclass , so you would have to use it on your base class, if you can add to it those properties. Adjusting your pastebin mapping linked in comment:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
                   assembly="Entities.NHibernate" 
                   namespace="Entities.NHibernate.SPAssociationAggregate"
                           default-access="property">

  <!-- Class definition -->
  <class name="SPAssociationBase" table="SPAssociation" lazy="false">
    <!-- Composite primary key -->
    <composite-id>
      <key-property name="BeginDate" type="date" />
      <key-property name="OrganizationId" />
      <key-property name="ProgramOrganizationId" />
      <key-property name="ProgramName" length="60" />
      <key-property name="ProgramTypeId" />
      <key-property name="SUSI" />
    </composite-id>

    <!-- Optimistic locking for aggregate root -->
    <version name="LastModifiedDate" type="timestamp" />

    <!-- Transient state detection -->
    <property name="CreateDate" type="DateTime" />

    <!-- Unique Guid-based identifier for aggregate root -->
    <property name="Id" />

    <!-- Properties -->
    <property name="EndDate" type="date" />
    <property name="ReasonExitedDescriptorId" />
    <property name="ServedOutsideOfRegularSession" />

    <!-- Collections -->
    <bag name="SPAssociationServices" cascade="all-delete-orphan" inverse="true" lazy="false">
      <key>
        <column name="BeginDate" />
        <column name="OrganizationId" />
        <column name="ProgramOrganizationId" />
        <column name="ProgramName" />
        <column name="ProgramTypeId" />
        <column name="SUSI" />
      </key>
      <one-to-many class="SPAssociationServiceForBase" />
    </bag>

    <!-- Extended properties -->
    <join table="SSEPAssociationExtension" optional="true">
      <key>
        <column name="BeginDate" />
        <column name="OrganizationId" />
        <column name="ProgramOrganizationId" />
        <column name="ProgramName" />
        <column name="ProgramTypeId" />
        <column name="SUSI" />
      </key>
      <property name="EventCode" />
      <property name="WrittenConsentDate" />
    </join>

    <!-- Derived classes -->
    <joined-subclass name="SESProgramAssociationAggregate.SESProgramAssociation" table="SESProgramAssociation" lazy="false">
      <key>
        <column name="BeginDate" />
        <column name="OrganizationId" />
        <column name="ProgramOrganizationId" />
        <column name="ProgramName" />
        <column name="ProgramTypeId" />
        <column name="SUSI" />
      </key>

      <!-- Properties -->
      <property name="IdeaEligibility" />
      <property name="DescriptorId" />
      <property name="HoursPerWeek" />
      <property name="SHoursPerWeek" />
      <property name="MultiplyD" />
      <property name="MFragile" />
      <property name="LastEvaluationDate" type="date" />
      <property name="ReviewDate" type="date" />
      <property name="BeginDate" type="date" />
      <property name="EndDate" type="date" />
      <property name="EventCode" />
      <property name="WrittenConsentDate" type="date" />
    </joined-subclass>
  </class>
</hibernate-mapping>

Side notes:

  • Better avoid composite key if possible. Or map them as component , override GetHashCode and Equals for them, ...
  • There is no need duplicating property names as column names if they are the same. And most property types can be inferred from the underlying class by NHibernate. If they match, better not bloat your mapping by specifying their type in mapping. (So I have left only string lengths in my example above, and date type, since there is no precise match between .Net date & time types and SQL ones.)
  • It is strange to "remap" your primary key as properties in subclass. You should inherit those properties from base class <id> , and so you should not have any need to map them again in the joined subclass.
  • Disabling lazy loading is not an usual practice with NHibernate. Lazy loading with NHibernate can benefit of batched loadings, which render it quite efficient. See my answer here for more details.
    Though with composite keys, you should map them as components for besting lazy loads. (Otherwise, accessing to one of the key property on an unloaded proxy will cause it to load.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM