Search code examples
c#nhibernatefluent-nhibernateone-to-onefluent-nhibernate-mapping

Fluent NHibernate Mapping: one-to-one (or none)


I have a following database scheme setup which I can't really change.

User
----
Id    (primary key)
[Some simple properties...]


UserAdditionalData
------------------
Id     (primary key)
[Some simple properties...] 
USERID (foreign key to User)

It's clear that the User table doesn't really have any recollection whether or not it is linked to a UserAdditionalData record, so I don't think I can call this a true one-to-one mapping here since they also don't share a mutually exclusive PK.

However, in practice, I would like to be able to work on a User object and for example check if it has a UserAdditionalData record and if so, access its properties.

I've set up my BDO as such:

public class User
{
    [Some simple properties...] 
    public virtual UserAdditionalData UserAdditionalData { get; set; }
}

public class UserAdditionalData
{
    [Some simple properties...] 
    public virtual User User { get; set; }  /* I have this here, 
                                               but I don't really ever 
                                               have to access it in this 
                                               direction */
}

I've set up my mapping as such:

    public UserMapping()
    {
        Table("USER");
        [Some simple properties...] 
        HasOne(x => x.UserAdditionalData).Cascade.None();
    }


    public UserExtraMapping()
    {
        Table("USER_ADDITIONAL_DATA");
        [Some simple properties...] 
        References(x => x.User, "USERID").Unique();
    }

This all compiles, but I see that my UserExtra object (when accessed via a User object) is always null. I've tried a lot of different ways to go about it, read a lot on implementing this as a one-to-many. However, I'm still not being able to get it to work.

Any help would be much appreciated.

Thanks!

[Small UPDATE]: I only have to query the database, not save to it if that's relevant in any way.


Solution

  • Based on your small update, I would go with a simplified mapping. We would profit from NHibernate real mapping power, and also optimize the User loading. All that because we do need Read-Only mapping.

    Firstly, we should introduce simple int property UserId on the Additional class

    // extra class is having an int property containig the foreign key
    public class UserAdditionalData
    {
        public virtual int UserId { get; set; }
    }
    
    // that would be the mapping:
    public UserExtraMapping()
    {
        ...
        Map(x => x.UserId, "USERID");
    }
    

    Now, we will use well optimized mapping for lazy loading many-to-one (I.e. in comparison with one-to-one which loads both ends always, here we will get the reference data only if really needed!)

    public UserMapping()
    {
        ...
        References(x => x.UserAdditionalData)
              .LazyLoad()
              .PropertyRef(e => e.UserId)
              .Not.Insert()
              .Not.Update()
              ;
    }
    

    So, for readonly I would do the best to use many-to-one mapping (References())

    see also: