21

How do I "turn on" cascading saves using AutoMap Persistence Model with Fluent NHibernate?

As in:

I Save the Person and the Arm should also be saved. Currently I get

"object references an unsaved transient instance - save the transient instance before flushing"

public class Person : DomainEntity
{
  public virtual Arm LeftArm { get; set; }
}

public class Arm : DomainEntity
{
  public virtual int Size { get; set; }
}

I found an article on this topic, but it seems to be outdated.

rmontgomery429
  • 14,660
  • 17
  • 61
  • 66

5 Answers5

13

Updated for use with the the current version:

public class CascadeAll : IHasOneConvention, IHasManyConvention, IReferenceConvention
{
    public void Apply(IOneToOneInstance instance)
    {
        instance.Cascade.All();
    }

    public void Apply(IOneToManyCollectionInstance instance)
    {
        instance.Cascade.All();
    }

    public void Apply(IManyToOneInstance instance)
    {
        instance.Cascade.All();
    }
}
Kristoffer
  • 834
  • 6
  • 22
  • 1
    For "public void Apply(IOneToManyCollectionInstance instance) ", I also find it useful to have "instance.inverse();" in addition to "instance.Cascade.All()." – Antony Jul 14 '11 at 18:26
13

This works with the new configuration bits. For more information, see http://fluentnhibernate.wikia.com/wiki/Converting_to_new_style_conventions

//hanging off of AutoPersistenceModel    
.ConventionDiscovery.AddFromAssemblyOf<CascadeAll>()


public class CascadeAll : IHasOneConvention, IHasManyConvention, IReferenceConvention
{
    public bool Accept( IOneToOnePart target )
    {
        return true;
    }

    public void Apply( IOneToOnePart target )
    {
        target.Cascade.All();
    }

    public bool Accept( IOneToManyPart target )
    {
        return true;
    }

    public void Apply( IOneToManyPart target )
    {
        target.Cascade.All();
    }

    public bool Accept( IManyToOnePart target )
    {
        return true;
    }

    public void Apply( IManyToOnePart target )
    {
        target.Cascade.All();
    }
}
Martin Atkins
  • 62,420
  • 8
  • 120
  • 138
Matt Florence
  • 688
  • 6
  • 9
4

The easiest way I've found to do this for a whole project is to use DefaultCascade:

.Conventions.Add( DefaultCascade.All() );     

Go to "The Simplest Conventions" section on the wiki, for this, and a list of others.

Here's the list from the Wiki:

Table.Is(x => x.EntityType.Name + "Table")
PrimaryKey.Name.Is(x => "ID")
AutoImport.Never()
DefaultAccess.Field()
DefaultCascade.All()
DefaultLazy.Always()
DynamicInsert.AlwaysTrue()
DynamicUpdate.AlwaysTrue()
OptimisticLock.Is(x => x.Dirty())
Cache.Is(x => x.AsReadOnly())
ForeignKey.EndsWith("ID")

A word of warning - some of the method names in the Wiki may be wrong. I edited the Wiki with what I could verify (i.e. DefaultCascade and DefaultLazy), but can't vouch for the rest. But you should be able to figure out the proper names with Intellisense if the need arises.

RedGreenCode
  • 2,195
  • 1
  • 25
  • 33
Tom Bushell
  • 5,865
  • 4
  • 45
  • 60
3

The Convention Method Signatures have changed. For the new answer that does exactly what this question asks see THIS QUESTION.

Community
  • 1
  • 1
Glenn
  • 1,234
  • 2
  • 19
  • 33
1

You can also make cascading the default convention for all types. For example (using the article you linked to as a starting point):

autoMappings.WithConvention(c =>  
  {  
    // our conventions
    c.OneToOneConvention = o => o.Cascade.All();
    c.OneToManyConvention = o => o.Cascade.All();
    c.ManyToOneConvention = o => o.Cascade.All();
  });
Oenotria
  • 1,692
  • 11
  • 24