views:

27

answers:

1

Hi all,

I have a class called User. User can have one or more roles, defined in an bitmask enum. The user has a Role property that i can use via:

user.Roles = Roles.User | Roles.Other;

In the database I have a Users table and a User_Roles table. For every role that a user has, i want to store it in the Users_Roles table with the UserID and the string representation of the Role. for example, the data stored for the previous example would be:

User_Roles
---
UserID   Role
23       User
23       Other

how would i create the mapping on this? i've read the examples, and they all seem to map it straight to the User table.

A: 

NHibernate will not map a single value to a table, but you can use a Linq-to-object projection on the enum:

protected virtual ICollection<Roles> RolesCollection
{
    get
    {
        return Enum.GetValues(typeof(Roles))
                   .Cast<Roles>()
                   .Where(r => (r & Roles) == r)
                   .ToList();
    }
    set
    {
        Roles = value.Aggregate((r1, r2) => r1 | r2);
    }
}

And then map it as a set:

<set name="RolesCollection" table="User_Roles">
  <key column="UserID" />
  <element type="Roles" /><!--you might have to qualify the type-->
</set>

As you can see, you don't even need to make the collection property public, so this is transparent to the rest of your application.

Diego Mijelshon
Can't I create a fluent convention or something to do it automatically though?
bryan costanich
Fluent can do 90% of what XML can do, and this is a simple case so it should be possible (I'm not using it, so I don't know how to create the convention). But you still need to implement the projection.
Diego Mijelshon
I thought the whole point of conventions was to handle things like this. that way you don't need to project.
bryan costanich
Fluent is just a mapping layer for NH. It can't add functionality to NH.
Diego Mijelshon