FluentNHibernate and Enums - nhibernate

I have an enum called Permissions. A user can be assigned permissions, or permissions can be asigned to a role and the user can be given a role.
User and Role both have a property like this:
public virtual IList<Permission> Permissions { get; set; }
I want to use an enum for Permissions so in my code I can do things like
public static bool UserHasPermission(Permission.DeleteUser)
Right now I have about 50 different permissions in my enum. It would be nice if I didn't have to populate a mirror set of data in the database. My enum looks like this:
public enum Permission
{
//site permissions 1-99
[StringValue("View Users")]
ViewUser = 1,
[StringValue("Add User")]
AddUser = 2,
[StringValue("Edit User")]
EditUser = 3,
[StringValue("Delete User")]
DeleteUser = 4
...
}
Currently, I have a table for Permissions that is the PermissionId (int) and PermissionName (varchar (50)).
Here are my tables on the roles side. The user side is exactly the same as far as permissions go:
CREATE TABLE dbo.Roles
(
RoleId int IDENTITY(2,1) NOT NULL,
RoleName varchar (50) NOT NULL,
CONSTRAINT PK_Roles PRIMARY KEY CLUSTERED (RoleId)
)
CREATE TABLE dbo.RolePermissions
(
RolePermissionId int IDENTITY(1,1) NOT NULL,
RoleId int NOT NULL,
PermissionId int NOT NULL,
CONSTRAINT PK_RolePermissions PRIMARY KEY CLUSTERED (RolePermissionId),
CONSTRAINT FK_RolePermissions_Roles FOREIGN KEY (RoleId) REFERENCES Roles(RoleId),
CONSTRAINT U_RolePermissions UNIQUE(RoleId, PermissionId)
)
Then, I have a permissions tble in case I need it, but I just don't get how to map either the id field in RolePermissions or the Permissions table back to the enum.
CREATE TABLE dbo.Permissions
(
PermissionId int NOT NULL,
PermissionName varchar (50) NOT NULL,
CONSTRAINT PK_Permissions PRIMARY KEY CLUSTERED (PermissionId)
)
Can I map the enum to the table?
Should I even map it, or should I just take out the Permissions table and in UserPermissions and RolePermissions leave PermissionId just an int and map the into to the enum?
If I keep the Permissions table, is there a way for nhibernate to autopopulate the data in the Permissions table from the data in the enum?
Right now, I have no mapping to the permission enum, other than something like this:
HasManyToMany(x => x.Permissions)
.WithParentKeyColumn("RoleId")
.WithChildKeyColumn("PermissionId")
.WithTableName("RolePermissions")
.LazyLoad()
.Cascade.All();
Unfortunately, this causes an error:
An association from the table
RolePermissions refers to an unmapped
class:
GotRoleplay.Core.Domain.Model.Permission
What am I doing wrong with enums? Is there a standard way or best practice for using them with fluentnhibernate when the enum is a list of values on the object and not just a single value?

Just to make sure I understand, are you trying to just map an enum property in your class to a field in a database? If that's it, then here's an example of how to do that:
public class Toy {
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
public virtual ToyCondition Condition { get; set; }
}
public enum ToyCondition {
New,
Used
}
public class ToyMap : ClassMap<Toy> {
public ToyMap() {
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.Condition).CustomTypeIs(typeof(ToyCondition));
}
}
After that you can get, set and do logic with the Condition property just like normal using the ToyCondition enum.
Toy newToy = new Toy();
newToy.Condition = ToyCondition.New;
toyRepository.Save(newToy);
In the database for the Condition field, it should be an int. I hope this made sense and answers your question. Sorry if it doesn't and I'm way off.
Edit:
Sorry I just noticed you asked this question and some one gave you the same answer as me. I don't think I can help you this. :(

So, after a few days of talking to other developers, digging around online, and posting to the FluentNHibernate group on google, I have discovered that collections of enums are currently not exactly supported. If there is a way to do what I want to do, well, it's undocumented or a workaround.
So, I went back to the drawing board with what I was doing and really thought about it. Basically, my only choice was to use a class for my permissions. But, I want to use my enum in code, and that's when it hit me. The PermissionId field can be converted from an int to the enum and vice versa. Also, using some logic I have done before when using an enum of roles with the built in ASP.NET provider, I can write an administrative tool that will build permissions based on what is in my enum.
First, I renamed my enum.
public enum PermissionCode
{
//site permissions 1-99
[StringValue("View Users")]
ViewUser = 1,
[StringValue("Add User")]
AddUser = 2,
[StringValue("Edit User")]
EditUser = 3,
[StringValue("Delete User")]
DeleteUser = 4,
}
Then, I created a new Permission class. This class mirrors the database and is simply an int Id and a string name. However, I added one property to convert that id into my PermissionCode enum.
public class Permission
{
public virtual int PermissionId { get; set; }
public virtual string PermissionName { get; set; }
public virtual PermissionCode PermissionCode
{
get
{
return (PermissionCode)PermissionId;
}
}
}
Then, in my User and Role objects, I reference Permission, and I can still do matchups like bool UserHasPermission(PermissionCode.DeleteUser);
Then in global.asax, on Application_Start I will check the webconfig for a flag that will indicate if the permissions need to be rebuilt. This way I can enable the rebuild only when I need to without having to have a permission to get in and possibly needing to deal with an error. This means I only maintain a single list of permissions in my enum, which is ideal.
Granted, the overall approach isn't as slick as I wanted, but it works. Does anyone have any other suggestions?

Related

NHibernate configuration for uni-directional one-to-many relation

I'm trying to set up a relationship as follows. Each Master item has one or more Detail items:
public class Detail {
public virtual Guid DetailId { get; set; }
public virtual string Name { get; set; }
}
public class Master {
public virtual Guid MasterId { get; set; }
public virtual string Name { get; set; }
public virtual IList<Detail> Details { get; set; }
}
And Mappings:
public class MasterMap : ClassMap<Master>
{
public MasterMap()
{
Id(x => x.MasterId);
Map(x => x.Name);
HasMany(x => x.Details).Not.KeyNullable.Cascade.All();
}
}
public class DetailMap : ClassMap<Detail>
{
public DetailMap()
{
Id(x => x.Id);
Map(x => x.Name);
}
}
The Master database table is:
masterId uniqueidentifier NOT NULL
name nvarchar(max) NULL
and Detail is:
DetailId uniqueidentifier NOT NULL
name nvarchar(max) NULL
MasterId uniqueidentifier NULL
foreign key (masterId) references [Master]
I don't really care to have a link from Detail back to Master -- in otherwords, Detail objects on their own are just not interesting to my domain layer. They will always be accessed via their Master object.
Using code like this:
Master mast = new Master
{
MasterId = new Guid(),
Name = "test",
Details = new List<Detail>
{
new Detail { .DetailId = new Guid(), .Name = "Test1" },
new Detail { .DetailId = new Guid(), .Name = "Test1" }
}
};
using (transaction == Session.BeginTransaction)
{
Session.Save(mast);
transaction.Commit();
}
This works great, except for a crazy limitation outlined in this post: NHibernate does an INSERT and puts Detail.MasterId as NULL first, then does an UPDATE to set it to the real MasterId.
Really, I don't want Detail entries with NULL MasterIds, so if I set the MasterId field to NOT NULL, the INSERT to Detail will fail, because as I said NHibernate is trying to put in MasterId = NULL.
I guess my question boils down to this:
How can I get the above code sample to work with my existing domain model (eg, without adding a Detail.Master property), and the Detail.MasterId field in the database set to NOT NULL?
Is there a way to get Nhibernate to just put the correct MasterId in the initial INSERT, rather than running an UPDATE afterwards? Is there rationale somewhere for this design decision? -- I'm struggling to see why it would be done this way.
NH3 and above allow to correct save entities in case of uni-directional one-to-many mapping without annoying save null-save-update cycle, if you set both not-null="true" on <key> and inverse="false" on <one-to-many>
FluentNHibernate code snippet for that:
public class MasterMap : ClassMap<Master>
{
public MasterMap()
{
Id(x => x.MasterId);
Map(x => x.Name);
HasMany(x => x.Details)
.Not.Inverse() //these options are very
.Not.KeyNullable() //important and work only if set together
.Not.KeyUpdate() //to prevent double update
.Cascade.All();
}
}
You can't. To quote the link from my answer on the other question you linked to:
Very Important Note: If the <key> column of a <one-to-many> association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true". See the discussion of bidirectional associations later in this chapter.
Edit: as Hazzik has rightly pointed out, this has changed in NHibernate 3 and above. The docs sadly haven't been updated, so here's Hazzik:
[If you] set inverse="false" and not-null on <key>, NH3 and above will perform only two inserts insead of insert-insert-update.
The reason NHibernate does it this way is because:
When it saves the detail it only knows about the stuff the detail knows about. So any master references which happen in the background are ignored.
Only when the master is saved it sees the relation and updates the elements of the collection with the id of the master.
Which is from an object oriented point of view logical. However from a saving point-of-view is slightly less logical. I suppose you can always file a bug report, or look if it might have been filed already and ask them to change it. But I suppose they have their specific (design/domain) reasons.

Writing computed properties with NHibernate

I'm using NHibernate 2.1.2 + Fluent NHibernate
I have a ContactInfo class and table. The Name column is encrypted in the database (SQL Server) using EncryptByPassphrase/DecryptByPassphrase.
The following are the relevant schema/class/mapping bits:
table ContactInfo(
int Id,
varbinary(108) Name)
public class ContactInfo
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class ContactInfoMap : ClassMap<ContactInfo>
{
public ContactInfoMap()
{
Id(x => x.Id);
Map(x => x.Name)
.Formula("Convert(nvarchar, DecryptByPassPhrase('passphrase', Name))");
}
}
Using the Formula approach as above, the values get read correctly from the database, but NHibernate doesn't try to insert/update the values when saving to the database (which makes sense).
The problem is that I would like to be able to write the Name value using the corresponding EncryptByPassPhrase function. I'm unsure if NHibernate supports this, and if it does, I haven't been able to find the correct words to search the documentation effectively for it.
So... how can I write this computed property back to the database with NHibernate?
Thanks in advance!
A property mapped to a formula is read-only.
A named query wrapped up in a ContactInfoNameUpdater service might be one way to solve the problem.

FluentNhibernate Mapping of lookup table in to properties of Parent Object

Using FluentNhiberante is there a way to map the following:
Parent Table (Employee)
EmployeeId INT Primary Key
FirstName
LastName
EmployeeTypeId
Lookup Table (EmployeeType)
EmployeeTypeId INT Primary Key
EmployeeTypeDescription
My class is defined as:
public class Employee
{
int EmployeeId {get; set;}
...
string EmployeeTypeDescription {get; set;}
}
Is there a way via the FluentNhibernate mapping to populate the EmployeeTypeDescription property in the Employee object from the EmployeeTypeDescription table by looking up using the EmployeeTypeId column in Employee?
I'm pretty sure the normal and proper way to do this is by using References in the mapping file and then by adding a EmployeeType property to the Employee class and accessing the description using Employee.EmployeeType.EmployeeTypeDescription. I'm unable to change the code to do that at this time so am wondering how to just set the EmployeeTypeDescription property for now.
it should be possible tweaking the examplecode below:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
...
Join("EmployeeType", join =>
{
join.KeyColumn("EmployeeTypeId");
join.Map(k => k.TherapieOK, "somecolumn"));
}
...
}
}
You can map the class to a view.
You're correct as far as the normal way to do this.

How can I model this object hierarchy in Fluent NHibernate without violating DDD principles?

I am trying to build a domain model that will allow me to manage Contracts.
The Contract class is my aggregate root, and it has a single property right now, which is Reviewers.
Reviewers, in the context of the Contract, each have a property to it's parent Contract, and a First Name, Last Name, and Login. The reason they have these properties is so I can have the user select which Reviewers they want on a Contract.
The database that I'm tying my domain model to already exists, and it's a legacy system that I'm trying to extend.
It has a Contract Table, and a Reviewer Table.
The thing I haven't mentioned up until this point, is that Reviewers are actually Users in the system. So there's actually a third table involved, which is Users.
I have been able to map my Contract Table easily with FNH.
It looks something like this:
public class ContractMapping: ClassMap<Contract>
{
public ContractMapping()
{
Id(c => c.Id);
HasMany(c => c.AdditionalReviewers);
}
}
But I'm not sure how to model my Reviewers, because they are in fact Users as well. So my object model looks like this:
public class Reviewer: User
{
public virtual Guid Id { get; set; }
public virtual Contract Contract { get; set; }
}
public class User
{
public virtual Guid Id { get; set; }
public virtual string Login { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
}
I've been able to map my User class properly, and it looks something like this:
public class UserMapping: ClassMap<User>
{
public UserMapping()
{
Id(u => u.Id);
Map(u => u.Login);
Map(u => u.FirstName);
Map(u => u.LastName);
}
}
and I believe I want to map my Reviewer class like this:
public class ReviewerMapping: SubclassMap<Reviewer>
{
public ReviewerMapping()
{
Table("Reviewer");
//Id(r => r.Id).Column("ReviewerId"); <- won't compile
References(r => r.Contract).Column("ContractId");
}
}
So the problem I'm having is this:
The relationship between the User table and the Reviewer table is one to many. Meaning, for a given User there may be many Reviewer records. Why? Because a User has to be a Reviewer for a specific Contract. This causes an issue with the mapping, though, because the primary key for my Reviewer and the primary key for my User are completely different values, by necessity.
Also, because of the way I'm using Reviewer, when I create a new Reviewer, what I'm really trying to do is to associate a User with a Contract. I am not trying to create an entirely new User in the database.
What is the correct way for me to map Reviewer, knowing that in my domain model it is a subclass of User?
Sounds like a the Reviewer is not really modelling a person, but modelling a role or assignment the User takes on. I'd say your domain model is flawed in this aspect. Tweak Reviewer to be an association class between a User and a Contract.
I don't think Reviewer should inherit from User in the scenario you've described. I would have the Reviewer class hold a User object instead (composition over inheritance).
If it helps you conceptualize it better, rename Reviewer to Review. That way you can stop thinking about it as a User since it really isn't (multiple Reviewers in your current domain can be the same User, which doesn't make much sense).

Fluent NHibernate Map Enum as Lookup Table

I have the following (simplified)
public enum Level
{
Bronze,
Silver,
Gold
}
public class Member
{
public virtual Level MembershipLevel { get; set; }
}
public class MemberMap : ClassMap<Member>
{
Map(x => x.MembershipLevel);
}
This creates a table with a column called MembershipLevel with the value as the Enum string value.
What I want is for the entire Enum to be created as a lookup table, with the Member table referencing this with the integer value as the FK.
Also, I want to do this without altering my model.
To map an enum property as an int column, use method CustomType.
public class MemberMap : ClassMap<Member>
{
Map( x => x.MembershipLevel ).CustomType<int>();
}
In order to keep the enum and lookup table in sync, I would add the lookup table and data to your sql scripts. An integration test can verify that the enum and lookup table values are the same.
If you wanted SchemaExport to create this table, add a class and mapping for it.
public class MembershipLevel
{
public virtual int Id { get; set; }
public virtual string Code { get; set; }
}
public class MembershipLevelMap : ClassMap<MembershipLevel>
{
Id( x => x.Id );
Map( x => x.Code );
}
If you are creating the table with SchemaExport, you will need to populate it as well:
foreach (Level l in Enum.GetValues( typeof( Level ))) {
session.Save( new MembershipLevel{ Id = (int) l, Code = l.ToString() });
}
I wouldn't do that because your Enum declaration is not dynamic, or simpler, it doesn't change without recompiling, while your lookup table may change at any moment. If the Enum's and lookup table's values don't match, what's next?
Another reason is if you change the Enum (in code), you'd have to synchronise it with the database table. Since Enums don't have an incremental key (PK), they can't be synchronised so simple. Let's say you remove one Enum member from your code and recompile it, what is supposed to happen? And if you change a value?
I hope I made my objections to this approach clear. So I strongly recommend storing the name or the value of your enum members. To store it by name, just map like this:
public class MemberMap : ClassMap<Member>
{
Map(x => x.MembershipLevel, "level")
.CustomType<GenericEnumMapper<Level>>()
.Not.Nullable();
}
To store the values, do as #Lachlan posted in his answer.
Or if you really need a lookup table and wants to use an Enum with strict checking, create a normal model with PK (or use value for this), KEY and VALUE. Create your enum with your static members, and make the application query the database for the names and values when you start it. If things don't match, do whatever you need. Additionally, this doesn't guarantee your table won't change while your program is running, so you better be sure it doesn't.