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

发布于 2024-09-26 05:41:27 字数 11268 浏览 2 评论 0原文

我有一个名为“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>

I've got a class named 'Entity', which can be individuals or organizations. I have a few other classes that are descendants of Entity, which have their properties defined in extension tables in my database. One of my descendants is named 'User'.

A really truncated example of my table structure:

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

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

Using NHibernate.Linq, I fetch an instance of a non-User entity like this:

Session.Get<Entity>(myIdValue);

The resulting SQL always joins the extension tables and includes the additional columns found in the extension tables.

When I'm asking for an instance of Entity, I really don't want one of its descendants.

Can anyone point me to my mistake?

By popular demand, here's the mapping file for the Entity class hierarchy I'm referencing:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

烛影斜 2024-10-03 05:41:27

你的错误是你的数据库设计得很糟糕。您正在使用每个子类一个表的映射策略,但您已将其应用于许多明显不相关的类。组织如何拥有名字或姓氏?

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

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

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

Your mistake is that your database is poorly designed. You are using a table-per-subclass mapping strategy but you have applied it to many apparently unrelated classes. How can an Organization have a first or last name?

When you get an Entity, NHibernate has to join all the tables in the inheritance tree because it doesn't know what concrete type to return. If you get a User or an Organization it will only join to one other table as expected.

Is Entity an abstract class? You can't get concrete objects of type Entity because the abstract class can't be constructed.

Edited to add: After seeing the mapping files, I really think you should reconsider your design. This is not a good or reasonable use of inheritance. If you really want to continue with this model, I would suggest keeping the abstract base class but not mapping it. But I think this design has much deeper problems than that.

太阳哥哥 2024-10-03 05:41:27

Polymorphism="explicit" 应该放入我的类声明中。 NHibernate 中默认多态性是隐式的。

Polymorphism="explicit" should have been put into my class declaration. Polymorphism is implicit by default in NHibernate.

不必在意 2024-10-03 05:41:27

如果不进行连接,NHibernate 就不知道要返回一个 User 或 Entity 实例。您无法避免这种加入。当您保存用户时,您会恢复一个用户。如果您不想“找回用户”,您可以保存实体而不是用户。

Without making the join, NHibernate does not know to return you a User or Entity instance. You cannot avoid this join. When you save a user, you get back a user. If you don't want to "get back a user", you can save an entity instead of a user.

迷鸟归林 2024-10-03 05:41:27

您必须告诉您的配置文件您想要延迟加载


哦。所以事实证明,当我回答时我并没有正确醒来:)

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

You must tell your config files that you want lazy-loading


Doh. So it turns out i wasn't correctly awake when i answered :)

I searched a bit about the subject and can point you towards this article by mookid (i guess he's here on SO too) thats confirms what Jamie Ides is saying which is that basically you may have a code smell here. Perhaps reconsidering the classes and their mapping could be a better idea.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文