views:

573

answers:

3

I have a table called UserPermissions with a FK to the users table by userId and then a string column for the string value of an enum.

The error I am seeing is NHibernate.MappingException: An association from the table UserPermissions refers to an unmapped class: GotRoleplay.Core.Domain.Model.Permission

My Permission Enum:

    public enum Permission
{
    [StringValue("Add User")]
    AddUser,

    [StringValue("Edit User")]
    EditUser,

    [StringValue("Delete User")]
    DeleteUser,

    [StringValue("Add Content")]
    AddContent,

    [StringValue("Edit Content")]
    EditContent,

    [StringValue("Delete Content")]
    DeleteContent,
}

The property in my User class:

public virtual IList<Permission> Permissions { get; set; }

My database table:

CREATE TABLE dbo.UserPermissions
(
UserPermissionId      int                 IDENTITY(1,1) NOT NULL,
UserId       int     NOT NULL,
PermissionName     varchar (50)        NOT NULL,

CONSTRAINT PK_UserPermissions PRIMARY KEY CLUSTERED (UserPermissionId),
CONSTRAINT FK_UserPermissions_Users FOREIGN KEY (UserId) REFERENCES Users(UserId),
CONSTRAINT U_User_Permission UNIQUE(UserId, PermissionName)
)

My attempt at mapping the permissions property of my user object:

HasManyToMany(x => x.Permissions)
             .WithParentKeyColumn("UserId")
             .WithChildKeyColumn("PermissionName")
             .WithTableName("UserPermissions")
             .LazyLoad();

What am I doing wrong that it can't map the permission to a list of enum values?

+1  A: 

You need to specify the type so that NHibernate can convert the value in the table to a member of the Permission enum.

HasManyToMany(x => x.Permissions)
         .WithParentKeyColumn("UserId")
         .WithChildKeyColumn("PermissionName")
         .WithTableName("UserPermissions")
         .LazyLoad()
         .CustomTypeIs(typeof(Permission));

Edited to add: I'm sorry, I should have noticed that you had this as ManyToMany. That's not possible: You can't have a Users collection (other side of m:m) hanging off an enum. You need to define this as 1:m or create a Permission table and class and map that as m:m.

Jamie Ide
I tried using your suggestion and CustomTypeIs does not exist as a valid option. I tried instead using .CollectionType(typeof(Permission)) but I still see the same error: An association from the table UserPermissions refers to an unmapped class: GotRoleplay.Core.Domain.Model.Permission
Josh
A: 

I thought I would post the code that I chose for my solution. It's only a workaround. I wish Fluent would support Enum lists, but until it does, here's a possible solution:

The Enum - This is my enum, your standard enum.

public enum PermissionCode
{
    //site permissions 1-99
    ViewUser = 1,

    AddUser = 2,

    EditUser = 3,

    DeleteUser = 4
}

Next, I have my Permission class.

public class Permission
{
    public virtual int PermissionId { get; set; }
    public virtual string PermissionName { get; set; }

    public virtual PermissionCode PermissionCode 
    {
        get
        {
            return (PermissionCode)PermissionId;
        }
    }
}

As you can see, I have an ID and a name, and then a property that converts the Id into my PermissionCode enum.

The mapping looks like this:

public class PermissionMap : ClassMap<Permission>
{
    public PermissionMap() 
    {
        WithTable("Permissions");

        Id(x => x.PermissionId).GeneratedBy.Identity();

        Map(x => x.PermissionName);
    }
}

Since the PermissionCode property is derived, we don't do anything in the mapping.

My Table structure behind the mapping looks like this:

CREATE TABLE dbo.Permissions
(
    PermissionId        int                 NOT NULL,
    PermissionName      varchar (50)  NOT NULL,

    CONSTRAINT PK_Permissions PRIMARY KEY CLUSTERED (PermissionId)
)

If you wanted to use the name instead of the integer value, with some slight modifications you can. It depends on your personal preferences.

Josh
+1  A: 

here is the way which worked for me

HasMany(x => x.Licences)
                .WithTableName("DriverLicence")
                .AsElement("Level").AsBag();

look here for more information answer

dbones
Thanks for your post. I'll give it a try!
Josh