Search code examples
c#fluent-nhibernatefluent-nhibernate-mapping

c# Fluent nHibernate primary key is foreign key


My database layout looks like this:

Users
------------
|UserId    | <-PK
|FirstName |
|LastName  |
|MiddleName|
|Email     |
------------

Admins
------------
|UserId    | <-PK/FK to Users
------------

I Just want the ability to put in the unique ID to the Admins table to designate if that user is an Admin.

Here is my Fluent nHibernate code:

public class Users
{
    public virtual string UserId { get; set; }
    public virtual string FirstName { get; set; }
    ....
}

public class UserMappings : ClassMap<Users>
{
    public UserMappings()
    {
        Id(x => x.UserId).Column("UserId").Not.Nullable();

        Map(x => x.FirstName).Column("FirstName").Not.Nullable();
        Map(x => x.MiddleName).Column("MiddleName").Nullable();
        ....
    }
}

public class Admins
{
    public virtual Users User { get; set; }
}

public class AdminMappings : ClassMap<Admins>
{
    public AdminMappings()
    {
        Id(x => x.User).GeneratedBy.Foreign("Users");

        HasOne(x => x.User).Constrained();
    }
}

Unfortunately, when I run, I get this error:

Could not determine type for: SMAC.Users, SMAC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, for columns: NHibernate.Mapping.Column(User)

What I want is that if I do:

var admin;
admin.user <= instance of user to get name, email, etc...

How would I go about accomplishing this?

EDIT: I added this and I got it working though I don't know if its ideal:

public AdminMappings()
{
    Id(x => x.UserId).Column("UserId");
    HasOne(x => x.User).Constrained();
}

public UserMappings()
{
    Id(x => x.UserId).Column("UserId").Not.Nullable();
    Map(x => x.FirstName).Column("FirstName").Not.Nullable();
    Map(x => x.MiddleName).Column("MiddleName").Nullable();
    ...
    HasOne(x => x.Admin).Cascade.All();
}

public class Admins
{
    public virtual string UserId { get; set; }

    public virtual Users User { get; set; }
}

public class Users
{
    public virtual string UserId { get; set; }
    public virtual string FirstName { get; set; }
    ....
    public virtual Admins Admin { get; set; }
}

The only caveat is that I have to actually set the UserId and the User in order to save the Admin record rather then just the UserId and have it automatically pull the User record for me.


Solution

  • NHibernate can handle FK in primary keys

    public class AdminMappings : ClassMap<Admins>
    {
        public AdminMappings()
        {
            CompositeId().KeyReference(x => x.User, "UserId");
        }
    }
    

    Don't forget to implement equals and gethashcode on Admin appropiatly to use User.Id

    Update:

    To save a admin record with a given userId you can use session.Load<Users>(userId) which will not load the user record immediatly but satisfies the reference.