1

We have an Address entity, which has a foreign key that references a City table. An Address only references one City, but a City should be able to be referenced by many Addresses.

public class Address : Entity
{
    public virtual string AddressLine1 { get; set; }

    public virtual string AddressLine2 { get; set; }

    public virtual City City { get; set; }
}

public class City : Entity
{       
    public virtual string CityName { get; set; }
}

This is the Address class mapping.

public class AddressClassMapping : ClassMapping<Address>
{
    public AddressClassMapping()
    {
        this.Schema("dbo");
        this.Table("addresses");
        this.Cache(e => e.Usage(CacheUsage.ReadWrite));
        this.Id(e => e.Id, 
                m => { m.Column("id_address"); m.Generator(Generators.Native);});
        this.Property(e => e.AddressLine1, 
                      m => { m.Column("address_line_1"); m.NotNullable(true); });
        this.Property(e => e.AddressLine2, 
                      m => { .Column("address_line_2"); 
                      m.NotNullable(true); });
        this.ManyToOne(
            e => e.City,
            m =>
            {
                m.Column("id_city");
                m.Cascade(Cascade.All);
            });
    }
}

How should I change the class mappings so that:

  1. When I delete a City, all the Addresses with that City are deleted?
  2. When I delete an Address, the City is NOT touched?
  3. I can update an Address's City property by updating the foreign key?

So far, I have played with the Cascade property and have faced issues in which an update to an address's city caused updates to the City table, or I couldn't delete an address without violating a foreign key constraint.

Maria Ines Parnisari
  • 16,584
  • 9
  • 85
  • 130

1 Answers1

1

The many-to-one part, shown above (and discussed also here NHibernate Many-to-one cascade) could be set to these values

// xml
cascade="all|none|save-update|delete" 
// maping by code
Cascade.All | Cascade.None | Cascade.Persist | Cascade.Remove
// fluent 
Cascade.All() | Cascade.SaveUpdate() | Cascade.None() | Cascade.Delete() 

(read more here Mapping-by-Code - ManyToOne)

This will cover point number... well none of the above. Becuase none of the requirements is asking for cascading from Address to city.

The point 3:

  1. I can update an Address's City property by updating the foreign key?

is not about cascading. This is standard behviour, working even without cascading, because it changes the value in the Address table. Not touching the City at all.

To cover the point 2:

  1. When I delete an Address, the City is NOT touched?

Well, we should remove cascading at all, because ... it is not needed in this direction. But, this setting will fit to point 2

this.ManyToOne(
    e => e.City,
    m =>
    {
        m.Column("id_city");
        m.Cascade(Cascade.Persist);

To cover first point:

  1. When I delete a City, all the Addresses with that City are deleted?

we have to do a lot. We need to extend the POCO relations and introduce the one-to-many mapping. That will do what needed:

public class City : Entity
{       
    public virtual IList<Address> Addresses { get; set; }
}

mapping

mapping by code:

Set(x => x.Addresses, c =>
{
   ...
   c.Cascade(Cascade.All.Include(Cascade.DeleteOrphans));

fluent version

HasMany(x => x.Addresses)
    ...
    Cascade.AllDeleteOrphan();

(read more here Mapping-by-Code - Set and Bag)

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Thanks! Can you please explain to me the point of the second snippet? What does the `m.Cascade.SaveUpdate();` line do? – Maria Ines Parnisari Nov 01 '15 at 19:36
  • I am so sorry, I used fluent version (as your tags told me) while I should use mapping by code - fixed now, hope it helps – Radim Köhler Nov 01 '15 at 19:40
  • I still don't understand the purpose of the second snippet :( When I said "2. When I delete an Address, the City is NOT touched?" I meant to say the City row would still be kept. – Maria Ines Parnisari Nov 01 '15 at 21:45
  • In general. It is very exceptional to have cascade on many-to-one side. So, your solution is easy (as I've written down) - remove that cascade. Keep only that on City side. That will cover all your needs. – Radim Köhler Nov 02 '15 at 05:26