views:

284

answers:

2

I have the following db tables which I have simplified for this example:

Webpage Id, URLIdentifier

WebpageMetaData Webpage_id Keywords

Webpage_id is the primary key for the table and a foriegn key back to the webpage table.

I am then using Fluent NHibernate and its automapping feature to map these to the following POCO classes:

public class Webpage
{
    public virtual int Id { get; set; }
    public virtual string UrlIdentifier { get; set; }
    public virtual WebpageMetaData WebpageMetaData { get; set; }

}

public class WebpageMetaData
{
    public virtual int Id { get; set; }
    public virtual string Keywords{ get; set; }
    public virtual Webpage Webpage { get; set; }

}

I want to map these entities as one-to-one, so I override the automapping as follows:

public class WebpageMap : IAutoMappingOverride<Webpage>
{        
    public void Override(AutoMapping<Webpage> mapping)
    {
        mapping.HasOne(w => w.WebpageMetaData)
            .Not.Constrained()
            .Fetch.Join()
            .Cascade.All();
    }
}

public class WebpageMetaDataMap : IAutoMappingOverride<WebpageMetaData>
{
    public void Override(AutoMapping<WebpageMetaData> mapping)
    {
        mapping.Id(w => w.Id, "Webpage_id").GeneratedBy.Foreign("Webpage");

        mapping.HasOne(w => w.Webpage)
            .ForeignKey("Webpage_id")
            .Constrained()
            .Fetch.Join()
            .Cascade.None();
    }
}

I have tested these mappings and cascade rules and they work for selecting, inserting and updating. However when i perform a delete of the WebpageMetaData I get an exception saying that

"deleted object would be re-saved by cascade (remove deleted object from associations)[WebpageMetaData#524]"

The only way to stop the exception is by doing the following before saving:

webpageMetaData.Webpage.WebpageMetaData = null;

So I have to set a null reference to myself from my parent??! This seems wrong? have I got my mapping wrong?

Thanks.

Update 1: Please see the NH mappings that FLuent is producing, in case this is of help to the hard core NHibernator's :)

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" name="EveryPage.Core.Domain.Webpage, EveryPage.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Webpage`">
    <id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
      <column name="Id" />
      <generator class="identity" />
    </id>
    <one-to-one cascade="all" class="EveryPage.Core.Domain.WebpageMetaData, EveryPage.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" constrained="false" fetch="join" name="WebpageMetaData" />
    <property name="UrlIdentifier" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="UrlIdentifier" />
    </property>    
  </class>
</hibernate-mapping>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" name="EveryPage.Core.Domain.WebpageMetaData, EveryPage.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`WebpageMetaData`">
    <id name="Id" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" unsaved-value="0">
      <column name="Webpage_id" />
      <generator class="foreign">
        <param name="property">Webpage</param>
      </generator>
    </id>
    <one-to-one cascade="none" class="EveryPage.Core.Domain.Webpage, EveryPage.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" constrained="true" fetch="join" foreign-key="Webpage_id" name="Webpage" />
    <property name="Keywords" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Keywords" />
    </property>
  </class>
</hibernate-mapping>
+1  A: 

I think your mapping isn't quite right. If you take a look at the NH documentation, their example of using one-to-one for a parent-child relationship involves a many-to-one mapping (with unique=true) and a one-to-one mapping, not a pair of one-to-one mappings. (A pair of one-to-one mappings is for the case where two tables are associated using a shared PK)

I suggest you try changing your mapping to better match the example to see if that fixes the cascades.

Paul Batum
Thanks for your help Paul.However my two tables do share the same PK, this is the design I am after. So I am trying to use a pair of one-to-one mappings. However the cascade is not playing how I would have thought?!
j3ffb
Sorry I misunderstood. I can now see how your WebpageMetaDataMap has the same column name for the ID and the relationship. I can't see anything wrong with your mapping then. You might want to examine the XML that FNH is generating and then ask on the nhusers mailing list about how one-to-one cascades are supposed to work. Sorry I wasn't much help.
Paul Batum
Hi Paul, no problem, its good just to have someone else tell you that you haven't done anything obviously wrong, especially when your new to a technology!How do I get to the XML that FNH is creating for my mappings?Thanks
j3ffb
Use the ExportTo method demonstrated on the bottom of this wiki page:http://wiki.fluentnhibernate.org/Fluent_configuration
Paul Batum
A: 

Hm, Cascade-all-delete-orphan maybe?

Noel Kennedy
Thanks for your help, however I don't think delete orphan is an option with a one-to-one mapping, I think they apply to parent-child relationships? You cannot get an orphan in this type of relation, a WebpageMetaData cannot exist without a Webpage.
j3ffb