如何避免NHibernate中不必要的联接

如何避免NHibernate中不必要的联接,nhibernate,nhibernate-mapping,Nhibernate,Nhibernate Mapping,我有一个名为“实体”的类,可以是个人或组织。我还有一些其他类是Entity的后代,它们的属性在数据库的扩展表中定义。我的一个后代名为“User” 我的表结构的一个真正被截断的示例: Table: ENTITY Id - UniqueIdentifier LastName - Varchar(200) FirstName - Varchar(50) Table: USER Id - UniqueIdentifier (FK to Entity) Password - Varchar(20) 使

我有一个名为“实体”的类,可以是个人或组织。我还有一些其他类是Entity的后代,它们的属性在数据库的扩展表中定义。我的一个后代名为“User”

我的表结构的一个真正被截断的示例:

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);
Session.Get(myIdValue);
生成的SQL始终连接扩展表,并包含扩展表中的其他列

当我请求实体的一个实例时,我真的不想要它的一个后代

有人能指出我的错误吗

根据流行的需求,以下是我引用的实体类层次结构的映射文件:

<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>

您必须告诉您的配置文件您想要


Doh。所以当我回答:)的时候,我并没有完全清醒


我搜索了一些关于这个主题的信息,可以向你指出mookid(我猜他是),这证实了Jamie Ides所说的,基本上你可能有一种代码的味道。也许重新考虑类及其映射可能是一个更好的主意

如果不加入,NHibernate不知道返回用户或实体实例。您无法避免此加入。保存用户时,将返回一个用户。如果您不想“找回用户”,可以保存实体而不是用户。

您的错误在于数据库设计不当。您使用的是逐子类表映射策略,但您已经将其应用于许多显然不相关的类。一个组织如何能有名字或姓氏

当您获得一个实体时,NHibernate必须连接继承树中的所有表,因为它不知道返回什么具体类型。如果您得到一个用户或组织,它将只按预期加入到另一个表

实体是抽象类吗?无法获取实体类型的具体对象,因为无法构造抽象类


编辑添加:在看到映射文件后,我真的认为您应该重新考虑您的设计。这不是对继承的良好或合理的使用。如果您真的想继续使用这个模型,我建议保留抽象基类,但不要映射它。但是我认为这个设计有比这个更深的问题。

多态性=“explicit”应该放在我的类声明中。多态性在NHibernate中默认是隐式的。

为了进行实验,我删除了Linq,并使用“Entity obj=(Entity)Session.Get(typeof(Entity),Id);”获取了对象这导致了相同的SQL。如果可能的话,请在id中使用int而不是uniqueidentifier-稍后性能会更好…@Tahbaza id类型与此问题有什么关系?什么时候表现会更好?@Paco评论与回答问题没有直接关系,这就是为什么它是评论而不是回答。对于任何具有任何卷的表,如果在短4倍的键上加入,性能会更好……我认为这是默认值,因此我们可能需要查看“Entity”的表映射,我已经在这个类的映射文件上有default lazy=“true”。我应该多做点什么吗?我将添加本文中引用的测试,看看它们是否按应有的方式运行。@Tahbaza我也这么认为,但由于fluent nhibernate中存在一个奇怪的错误,我尝试详尽地进行诊断:)@david您是否尝试访问您的延迟加载实体。如果您这样做,这可能就是它试图加载子体的原因。延迟加载与继承无关mapping@Paco是的,的确如此。我错误地理解了这个问题,认为这些表描述的是关系映射,而不是继承。睡个好觉之后,错误就很明显了:我正试图实现一种逐层次表映射策略,使用联接表来声明在基类中找不到的其他属性。实体不是抽象类;它是一种具体的类型;它有一个抽象的祖先。组织和个人不是类型,它们是由内部的属性值区分的