1

I have a one-to-one mapping which I'm trying to express with Fluent NHibernate mappings. I know there are a LOT of similar questions/answers on the web but after hours I'm struggling to find an answer to my specific question.

I have a Member and Subscription object. A member can have 0..1 Subscriptions and a subscription instance can only ever pertain to a single member.

Here are my classes:

public class Member
{
    public Subscription Subscription { get; set; }
}

public class Subscription
{
    public Member Member { get; set; }

    public DateTime StartDate { get; set; }

    public DateTime FinishDate { get; set; }
}

Here are my mappings (fluent):

For Member:

mapping.HasOne(member => member.Subscription)
    .PropertyRef(subscription => subscription.Member).Cascade.SaveOrUpdate();

For Subscription:

mapping.References(subscription => subscription.Member)
   .Unique().Cascade.None();

There are a few requirements but I can't seem to fulfill them all:

  • That saving a Member cascades to Subscription.
  • Deleting a Subscription breaks the association on the Member.
  • Deleting a Subscription doesn't delete the Member.

If I set Cascade on Member the Subscription is saved, but deleting a Subscription throws an ObjectDeletedException.

Why can't NHibernate automatically remove the association to Subscription first, before applying the cascade on Member?

Matt B
  • 8,315
  • 2
  • 44
  • 65
  • Isn't what you're looking for `Cascade.DeleteAllOrphans` on member subscriptions? Then setting member's Subscription to Null should remove the subscription from the DB. Though if you're looking to do something like `Session.Delete(subscription)` then you have to set the member's subscription to #null anyways. – Steve Py Jan 18 '13 at 12:09
  • I'd like it to work both ways. In the case of the latter, I was wondering why NHibernate couldn't just remove that association for me? – Matt B Jan 18 '13 at 12:12
  • NHibernate is not indented to change your member.Subscription just because some other code does session.Delete(sameSubscriptionInstance). – Oskar Berggren Jan 18 '13 at 12:29
  • Why not? Isn't calling session.Delete(subscription) doing that implicitly anyway? – Matt B Jan 18 '13 at 12:30

1 Answers1

2

The basic problem here is that this isn't a one-to-one relationship, it's a one-to-many with the many side constrained to 0 or 1. In a one-to-one relationship both entities must have the same primary key and this clearly isn't the case here. See this question.

I would model this as

public class Member
{
    private ICollection<Subscription> _subscriptions;

    public Name() { _subscriptions = new HashSet<Subscription>(); }

    public Subscription Subscription
    {
        get { return _subscriptions.SingleOrDefault(); }
        set
        {
            _subscriptions.Clear(); // may want to check if it contains value first
            value.Member = this; // assuming bidirectional association
            _subscriptions.Add(value); // null check value first
        }
    }
}

mapping.HasMany<Subscription>(Reveal.Member<Member>("_subscriptions"))
    .KeyColumn("MemberId")
    .AsSet().Inverse().Cascade.AllDeleteOrphan();

Also, I don't think you're using property-ref appropriately but that may be because you were mapping a one-to-one inappropriately.

Community
  • 1
  • 1
Jamie Ide
  • 48,427
  • 16
  • 81
  • 117
  • Seriously, I can't thank you enough. This fulfills all of the requirements. I formulated the original mappings after looking at this answer: http://stackoverflow.com/questions/2160324/nhibernate-bi-directional-one-to-one-mapping-problem and the links posted in that answer. My next question is - how long does it take to garner this level of understanding of NHibernate?? :p – Matt B Jan 18 '13 at 13:48
  • You're welcome. Answering questions on SO is one of the best ways to gain and maintain expertise and that's become my main motivation after I discovered that my points cannot be redeemed for valuable prizes. I've been working with NHibernate for 5 years and definitely have more to learn. One of the things I have learned is that true one-to-one relationships rarely exist and I've never used one in a real app. – Jamie Ide Jan 18 '13 at 14:04