Как избежать ненужных объединений в NHibernate - PullRequest
2 голосов
/ 06 октября 2010

У меня есть класс с именем «Entity», который может быть отдельным лицом или организацией. У меня есть несколько других классов, которые являются потомками Entity, чьи свойства определены в таблицах расширений в моей базе данных. Один из моих потомков называется «Пользователь».

Действительно усеченный пример структуры моей таблицы:

Table: ENTITY
Id - UniqueIdentifier
LastName - Varchar(200)
FirstName - Varchar(50)

Table: USER
Id - UniqueIdentifier (FK to Entity)
Password - Varchar(20)

Используя NHibernate.Linq, я получаю экземпляр объекта, не являющегося пользователем, например:

Session.Get<Entity>(myIdValue);

Полученный SQL всегда объединяет таблицы расширений и включает дополнительные столбцы, найденные в таблицах расширений.

Когда я запрашиваю экземпляр Entity, я действительно не хочу одного из его потомков.

Может кто-нибудь указать мне на мою ошибку?

По многочисленным просьбам вот файл сопоставления для иерархии классов сущностей, на которую я ссылаюсь:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <!-- AbstractEntity -->
  <class xmlns="urn:nhibernate-mapping-2.2" name="netfile.model.filer.entities.AbstractEntity, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="Entity" abstract="true" discriminator-value="AbstractEntity">
    <id name="Id" type="System.Guid">
      <column name="Id" />
      <generator class="guid.comb" />
    </id>
    <discriminator column="Type" type="string"/>
    <property name="Xref">
      <column name="Xref" />
    </property>
    <property name="Name">
      <column name="LastName" />
    </property>
    <property name="FiledAs">
      <column name="FiledAs" />
    </property>
    <property name="RestKey">
      <column name="RestKey" />
    </property>
    <property name="SearchText">
      <column name="SearchText" />
    </property>
    <many-to-one class="netfile.model.filer.dataspaces.Dataspace, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Dataspace">
      <column name="Dataspace_id" />
    </many-to-one>
    <many-to-one class="netfile.model.filer.Ownership, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Ownership">
      <column name="Ownership_id" />
    </many-to-one>
    <bag name="Descriptions" cascade="all-delete-orphan" inverse="true">
      <key>
        <column name="Entity_Id" />
      </key>
      <one-to-many class="netfile.model.filer.descriptions.AbstractDescription" />
    </bag>
    <!-- All Concrete Entity Types (Org, Ind, etc) -->
    <subclass name="netfile.model.filer.entities.Entity, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="Entity">
      <property name="FirstName">
        <column name="FirstName" />
      </property>
      <property name="IsIndividual">
        <column name="IsIndividual" />
      </property>
      <property name="IsLobbyistClient">
        <column name="IsLobbyistClient" />
      </property>
      <property name="MiddleName">
        <column name="MiddleName" />
      </property>
      <property name="Prefix">
        <column name="Prefix" />
      </property>
      <property name="Suffix">
        <column name="Suffix" />
      </property>
      <property name="Occupation">
        <column name="Occupation" />
      </property>
      <bag name="ContactMethods" cascade="all" inverse="true">
        <key>
          <column name="Entity_Id" />
        </key>
        <one-to-many class="netfile.model.common.OneLineAddress, netfile.model.common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </bag>
      <many-to-one cascade="all" class="netfile.model.common.AddressUS, netfile.model.common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="BusinessAddress">
        <column name="BusinessAddress_id" />
      </many-to-one>
      <many-to-one cascade="all" class="netfile.model.common.AddressUS, netfile.model.common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="MailingAddress">
        <column name="MailingAddress_id" />
      </many-to-one>
      <many-to-one cascade="all" class="netfile.model.common.AddressUS, netfile.model.common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="DisclosureAddress">
        <column name="DisclosureAddress_id" />
      </many-to-one>
      <many-to-one class="netfile.model.filer.entities.Entity, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Employer">
        <column name="Employer_id" />
      </many-to-one>
      <!-- Organization, Agency -->
      <!-- Agency -->
      <subclass name="netfile.model.filer.entities.Agency, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="Agency">
        <join table="Entity_Agency">
          <key>
            <column name="Entity_id" />
          </key>
          <property name="Abbreviation">
            <column name="Abbreviation" />
          </property>
          <many-to-one cascade="save-update" class="netfile.model.filer.entities.Entity, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="TechnicalSupportContact">
            <column name="TechnicalSupportContact_id" />
          </many-to-one>
        </join>
      </subclass>
      <!-- Committee -->
      <subclass name="netfile.model.filer.entities.campaign.Committee, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="Committee">
        <join table="Entity_Committee">
          <key>
            <column name="Entity_id" />
          </key>
          <property name="FilerId">
            <column name="FilerId" />
          </property>
        </join>
        <!-- GeneralPurposeCommittee -->
        <subclass name="netfile.model.filer.entities.campaign.GeneralPurposeCommittee, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="GeneralPurposeCommittee">
        </subclass>
        <!-- ControlledCommittee -->
        <subclass name="netfile.model.filer.entities.campaign.ControlledCommittee, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="ControlledCommittee">
          <bag name="ControllingOfficers" table="Entity_Links">
            <key>
              <column name="Source_Id" not-null="true"/>
            </key>
            <many-to-many class="netfile.model.filer.entities.Entity, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
              <column name="Target_Id" not-null="true"/>
            </many-to-many>
          </bag>
          <!-- PrincipalCampaignCommittee -->
          <subclass name="netfile.model.filer.entities.campaign.PrincipalCampaignCommittee, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="PrincipalCampaignCommittee">
          </subclass>
        </subclass>
      </subclass>
      <!-- User -->
      <subclass name="netfile.model.filer.entities.User, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="User">
        <join table="Entity_User">
          <key>
            <column name="Entity_id" />
          </key>
          <property name="ChallengeAnswer">
            <column name="ChallengeAnswer" />
          </property>
          <property name="ChallengeQuestion">
            <column name="ChallengeQuestion" />
          </property>
          <property name="Disabled">
            <column name="Disabled" />
          </property>
          <property name="Password">
            <column name="Password" />
          </property>
          <property name="PasswordResetKey">
            <column name="PasswordResetKey" />
          </property>
          <property name="Reference">
            <column name="Reference" />
          </property>
          <property name="SecurityLocked">
            <column name="SecurityLocked" />
          </property>
          <bag name="DataspacePermissions" cascade="all">
            <key>
              <column name="User_Id" />
            </key>
            <one-to-many class="netfile.model.filer.permissions.PermissionDataspace, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          </bag>
        </join>
        <subclass name="netfile.model.filer.entities.UserSupport, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="UserSupport">
          <join table="Entity_UserSupport">
            <key>
              <column name="Entity_id" />
            </key>
            <property name="CompanyName">
              <column name="CompanyName" />
            </property>
          </join>
        </subclass>
      </subclass>
    </subclass>
    <!-- MunicipalDecision, MunicipalDecisionSfo -->
    <subclass name="netfile.model.filer.entities.lobbyist.MunicipalDecision, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="MunicipalDecision">
      <join table="Entity_MunicipalDecision">
        <key>
          <column name="Entity_id" />
        </key>
        <property name="Description">
          <column name="Description" />
        </property>
        <property name="OutcomeSought">
          <column name="OutcomeSought" />
        </property>
      </join>
    </subclass>
    <!-- MunicipalDecisionSfo -->
    <subclass name="netfile.model.filer.entities.lobbyist.sfo.MunicipalDecisionSfo, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="MunicipalDecisionSfo">
      <join table="Entity_MunicipalDecision">
        <key>
          <column name="Entity_id" />
        </key>
        <property name="Description">
          <column name="Description" />
        </property>
        <property name="OutcomeSought">
          <column name="OutcomeSought" />
        </property>
        <property name="FileNumber">
          <column name="FileNumber" />
        </property>
        <many-to-one class="netfile.model.filer.settings.ownership.AgencyDefinedLobbyingSubjectArea, netfile.data.filer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="SubjectArea">
          <column name="SubjectArea_id" />
        </many-to-one>
      </join>
    </subclass>
  </class>
</hibernate-mapping>

Ответы [ 4 ]

3 голосов
/ 06 октября 2010

Ваша ошибка в том, что ваша база данных плохо спроектирована. Вы используете стратегию отображения таблиц на подклассы, но применили ее ко многим, очевидно, не связанным классам. Как организация может иметь имя или фамилию?

Когда вы получаете Entity, NHibernate должен объединить все таблицы в дереве наследования, потому что он не знает, какой конкретный тип возвращать. Если вы получите пользователя или организацию, она присоединится только к одной другой таблице, как и ожидалось.

Является ли Entity абстрактным классом? Вы не можете получить конкретные объекты типа Entity, потому что абстрактный класс не может быть создан.

Отредактировано, чтобы добавить: После просмотра файлов сопоставления, я действительно думаю, что вы должны пересмотреть свой дизайн. Это не хорошее или разумное использование наследства. Если вы действительно хотите продолжить эту модель, я бы предложил сохранить абстрактный базовый класс, но не отображать его. Но я думаю, что этот дизайн имеет гораздо более глубокие проблемы, чем этот.

2 голосов
/ 11 октября 2010

Полиморфизм = "явный" должен был быть помещен в мое объявление класса. Полиморфизм неявен по умолчанию в NHibernate.

0 голосов
/ 06 октября 2010

Без создания объединения NHibernate не знает, как вернуть вам экземпляр User или Entity.Вы не можете избежать этого присоединения.Когда вы сохраняете пользователя, вы возвращаете пользователя.Если вы не хотите «вернуть пользователя», вы можете сохранить сущность вместо пользователя.

0 голосов
/ 06 октября 2010

Вы должны указать свои конфигурационные файлы, которые вы хотите отложенная загрузка


Doh.Получается, что я не совсем проснулся, когда ответил:)

Я немного искал предмет и могу указать вам на эту статью от mookid (я думаю, он здесь, на SO тоже ), это подтверждает то, что говорит Джейми Идес, что в принципе у вас здесь может быть запах кода.Возможно, лучше было бы пересмотреть классы и их сопоставление.

...