Gareth
Gareth

Reputation: 2061

NHibernate won't delete orphaned object

I have a few classes that look like this

public class Token
{
    public int Id
    {
        get;
        set;
    }

    public ITokenInstance Instance
    {
        get;
        set;
    }
}

public interface ITokenInstance
{
    int Id
    {
        get;
        set;
    }

    Token Token
    {
        get;
        set;
    }
}

and mapping files


<class name="Token" >
   <id name="Id" >
      <generator class="hilo" />
   </id>

   <any name="Instance" meta-type="class" id-type="Int32" cascade="all-delete-orphan">
      <column  name="instance_type" />        
      <column name="instance_id" />
   </any>
</class>

<class name="TokenInstanceOne" >
   <id name="Id" >
      <generator class="hilo" />
   </id>

   <many-to-one name="Token" class="Token" column="token_id"/>
</class>

I have various implementations of the ITokenInstance interface, all looking in different tables but all using the same baisc structure as shown in the mapping. The problem is that whilst i can add a new ITokenInstance to a Token that has no instance set (null) and it will update correctly I can NOT add a new Instance to a Token that has already got an instance and then Update it, NHibernate will add the new instance i provide but not delete the now un-assigned instance. For example

Token token = Session.Get<Token>(4);
var instance = Session.Get<TokenInstanceOne>(1);
Assert.AreSame(token.Instance, instance);

var newInstance = new TokenInstanceOne();
token.Instance = newInstance;
newInstance.Token = token;
instance.Token = null;
Session.Flush();

This fires SQL to insert the new TokenInstance, and updates the token table to point at it, it does NOT delete the instance that was originaly set to the token. Does anyone know how I can instruct NHibernate to delete the original TokenInstance from the database

EIDT: I had missed something off that is now included in the code example (setting original TokenInstance's Token reference to null). Also just to clarify this is the SQL NHibernate is producing;

  1. INSERT INTO TokenInstanceOne (token_id, Id) VALUES (@p0, @p1); @p0 = '4', @p1 = '32768'
  2. UPDATE Token SET instance_type = @p0, instance_id = @p1 WHERE Id = @p2; @p0 = 'ClassLibrary1.TokenInstanceOne', @p1 = '32768', @p2 = '4'
  3. UPDATE TokenInstanceOne SET token_id = @p0 WHERE Id = @p1; @p0 = '', @p1 = '1'

Notice the last Update is setting token_id = '', what i need is for NHibernate to delete the row instead.

Upvotes: 0

Views: 1635

Answers (2)

Stefan Steinegger
Stefan Steinegger

Reputation: 64628

NHibernate does not implement a so called persistent garbage collection. There are situations where you need to remove entities explicitly. The cascade is for the case when you delete the Token.

This is your code:

var token = Session.Get<Token>(4);
Assert.IsNotNull(token.Instance);

// remove the old token
Session.Delete(token.Instance);

// assign the new token
var newInstance = new TokenInstance();
token.Instance = newInstance;
newInstance.Token = token;

// don't need to call update, the token is in the session.
// (except you turned off session flush)
// Session.Update(token);

Upvotes: 2

Krzysztof Kozmic
Krzysztof Kozmic

Reputation: 27374

Sorry, I misunderstood your question.

Have you tried setting inverse="true" on your any end? Alternatively move the cascade to th the other class' mapping.

Read

Upvotes: 0

Related Questions