如何避免NHibernate中不必要的联接
我有一个名为“实体”的类,可以是个人或组织。我还有一些其他类是Entity的后代,它们的属性在数据库的扩展表中定义。我的一个后代名为“User” 我的表结构的一个真正被截断的示例:如何避免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) 使
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是的,的确如此。我错误地理解了这个问题,认为这些表描述的是关系映射,而不是继承。睡个好觉之后,错误就很明显了:我正试图实现一种逐层次表映射策略,使用联接表来声明在基类中找不到的其他属性。实体不是抽象类;它是一种具体的类型;它有一个抽象的祖先。组织和个人不是类型,它们是由内部的属性值区分的