Ras
Ras

Reputation: 628

Nhibernate one-to-one relation return always null

I've two tables,

First one contain the Widget properties:

SQL

CREATE TABLE [dbo].[WidgetProperty](
    [WidgetPropertyID] [int] IDENTITY(1,1) NOT NULL,
    [WidgetID] [int] NOT NULL,
    [PropertyID] [int] NOT NULL,
    [PropertyIndex] [int] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [WidgetPropertyID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[WidgetProperty] ADD  DEFAULT ((1)) FOR [PropertyIndex]

HBM

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Nt.Engine.domain.WidgetProperty,Nt.Engine" table="WidgetProperty" lazy="true">
    <id name="WidgetPropertyID" column="WidgetPropertyID">
      <generator class="native" />
    </id>
    <property name="WidgetID" column="WidgetID" type="Int32" not-null="true" />
    <property name="PropertyID" column="PropertyID" type="Int32" not-null="true" />
    <property name="PropertyIndex" column="PropertyIndex" type="Int32" not-null="true" />
    <one-to-one name="PropertyDetail" cascade="all" foreign-key="none" class="Nt.Engine.domain.PropertyDetail,Nt.Engine"  />  
  </class>
</hibernate-mapping>

MODEL

public class WidgetProperty
{
    public virtual Int32 WidgetPropertyID { get; set; }
    public virtual Int32 WidgetID { get; set; }
    public virtual Int32 PropertyID { get; set; }
    public virtual Int32 PropertyIndex { get; set; }
    public virtual PropertyDetail PropertyDetail { get; set; }
}

Second one contains the data/details of each properties:

SQL

CREATE TABLE [dbo].[PropertyDetail](
    [PropertyID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
    [Length] [nvarchar](50) NOT NULL,
    [Type] [smallint] NOT NULL,
    [DefaultHtml] [nvarchar](600) NULL,
 CONSTRAINT [PK_PropertyDetail] PRIMARY KEY CLUSTERED 
(
    [PropertyID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[PropertyDetail] ADD  CONSTRAINT [DF__tblProper__Prope__276EDEB3]  DEFAULT ((1)) FOR [Type]

HBM

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Nt.Engine.domain.PropertyDetail,Nt.Engine" table="PropertyDetail" lazy="true">
    <id name="PropertyID" column="PropertyID">
      <generator class="native" />
    </id>
    <property name="Name" column="Name" type="string" length="50" not-null="true" />
    <property name="Length" column="Length" type="string" length="50" not-null="true" />
    <property name="Type" column="Type" type="byte" not-null="true" />
    <property name="DefaultHtml" column="DefaultHtml" type="string" length="600" not-null="false" />
  </class>
</hibernate-mapping>

MODEL

public class PropertyDetail
{
    public virtual Int32 PropertyID { get; set; }
    public virtual String Name { get; set; }
    public virtual String Length { get; set; }        
    public virtual byte Type { get; set; }
    public virtual String DefaultHtml { get; set; }
}

Basically in the first table, I've several rows for each WidgetID and the PropertyID refers to the PropertyDetail table one-to-one, so each WidgetProperty.PropertyID have just one row in PropertyDetail table. In the manager, if I call the object by widgetID (es: 4), the WidgetProperty.PropertyDetail is always null. Any hints?

Upvotes: 0

Views: 185

Answers (1)

Steve Py
Steve Py

Reputation: 34773

one-to-one references are used to join records that share the same PK, or where the secondary table has a FK that references the parent row. (using the property-ref option) In your case you want a column on the parent table to point to a child row. This is configured as a many-to-one relationship.

<many-to-one name="PropertyDetail" cascade="all" column="PropertyId" class="Nt.Engine.domain.PropertyDetail,Nt.Engine"  /> 

if you want a one-to-one then you need to replace the PropertyId on the PropertyDetail table with a WidgetPropertyId. Essentially if the PropertyId value equals the WidgetPropertyId then you'd actually get a row back with your current code, which is most certainly not what you'd be expecting. I.e. if you have a WidgetProperty /w ID 1234 and a PropertyId of 5, if there is a PropertyDetail with ID 1234 it would come back associated to Widget 1234 as the nature of one-to-one looks for matching PKs.

edit: made a correction above. If you want a one-to-one you can reverse the FK association, in your case add a WidgetPropertyId to your PropertyDetail and remove the PropertyId from WidgetProperty. From there you can set up a one-to-one from Widget to PropertyDetail as you had by removing the foreign-key and replacing it with property-ref to tell NH to link PropertyDetail via it's FK column rather than the PK:

<one-to-one name="PropertyDetail" cascade="all" property-ref="WidgetPropertyId" class="Nt.Engine.domain.PropertyDetail,Nt.Engine"  />  

Upvotes: 1

Related Questions