FluentNhibernate Mapping of lookup table in to properties of Parent Object - nhibernate

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.

Related

MVC4Demo.Models.Employee: : EntityType 'Employee' has no key defined

When I run Employee detail view then the following error is displayed. There are no issues related to database connectivity.
List itemDefine the key for this EntityType. Employees: EntityType: EntitySet 'Employees' is based on type 'Employee' that has no keys defined.
Code First would infer that a property is a primary key if the property is called Id or <class name>Id.
So, just add a such property to your model or you can also use [Key] attribute to map it a primary key.
For example:
public class Employee
{
[Key]
public int EmployeeId { get; set; }
//Other properties
}

Fluent NHibernate one-to-many disable foreign key constraint

I have this problem where I have a one-to-many relationship and I have to be able to delete the parent entity without it's children being deleted, nor their foreign key column set to NULL. But whenever I try deleting a parent, I get the foreign key constraint violation exception.
NHibernate.Exceptions.GenericADOException: could not execute update query[SQL: delete from [Customer]] ---> System.Data.SqlClient.SqlException: The DELETE statement conflicted with the REFERENCE constraint "FK7867CB245055157F"
I have a similar one-to-one relationship, where I have to be able to delete the entity on one end without the foreign key on the other end to be set to NULL and I solved this problem successfully by using NotFound.Ignore(). I have found several answers suggesting exactly this solution, but it seems to have no effect at all. I use my mapping to build the database BTW.
Here are my entities and mappings:
public class User : Entity
{
...
public virtual Customer Customer { get; set; }
...
}
public class Customer : Entity
{
...
public virtual string CustomerNumber { get; set; }
public virtual User User { get; set; }
public virtual IList<Vehicle> Vehicles { get; set; }
...
}
public class Vehicle : Entity
{
...
public virtual string SerialNumber { get; set; }
public virtual Customer Customer { get; set; }
...
}
I'm using AutoMapping and overrides:
public class UserMappingOverride : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
...
mapping.References(u => u.Customer).Column("CustomerNumber").NotFound.Ignore();
}
}
public class CustomerMappingOverride : IAutoMappingOverride<Customer>
{
public void Override(AutoMapping<Customer> mapping)
{
mapping.Id(u => u.Kundenummer).GeneratedBy.Assigned().Not.Nullable();
mapping.HasOne(u => u.User).PropertyRef(c => c.Customer);
mapping.HasMany(u => u.Vehicles).KeyColumns.Add("CustomerNumber")
.Cascade.None()
.Inverse();
}
}
public class VehicleMappingOverride : IAutoMappingOverride<Vehicle>
{
public void Override(AutoMapping<Vehicle> mapping)
{
mapping.Id(u => u.SerialNumber).GeneratedBy.Assigned().Not.Nullable();
mapping.References(u => u.Customer).Column("CustomerNumber").NotFound.Ignore();
}
}
As said, in the one-to-one relationship, in the mapping of User I use NotFound.Ignore(), which does as promised - allows me to delete a Customer without firing a constraint violation exception and still keep the values of "CustomerNumber" in the User table intact. The mapping of the relationship between the User and the Customer entities, simply does not produce a foreign key constraint in the database when the database is built from the mapping.
But the same thing doesn't work for my one-to-many relationship. Although the mapping is almost the same as my one-to-one relationship, and I use NotFound.Ignore() as suggested in similar questions here, this relationship still produces a foreign key constraint and I get a constraint violation exception when trying to delete a Customer. The only work-around is to manually delete the FK in the database or modify it by setting Enforce Foreign Key Constraint to False.
How can I get NHibernate to either not create this Foreign key constraint, or setting the Enfore Foreign Key Constraint to False, when building the database?
Best Regards
- Nikolaj
BTW: I'm not interested in comments about the overall design of the entities and relationships. They're designed like this based on constraints from the source of data, and this is the only plausible workaround. :-) I've found that a lot of answers in similar posts, focus on the design rater then of the question at hand.
you can not work around the FK in the database. My guess is that there is no FK from User to Customer. If you create the Schema from mappings then you'll need to disable the creation of the FK with mapping.References(u => u.Customer).ForeignKey("none");
Firo's answer pointed me in the right direction as how to get rid of the FK constraint. Adding .ForeignKey("none") to the Vehicle mapping didn't do it though. But adding a similar property to the Customer mapping solved my problem.
So the solution became:
mapping.HasMany(u => u.Vehicles).ForeignKeyConstraintName("none")

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.

FluentNHibernate and Enums

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?

NHibernate one way, one-to-many, mapping question

I have a scenario in NHibernate where I have a one-to-many relationship between entities Employee and EmployeeStatus.
Employee has properties eg: ID, Name and an IList of EmployeeStatus, whilst EmployeeStatus, for the purposes of this question, just has it's own ID and some free text.
I don't need to hold a reference to Employee from EmployeeStatus, the management of status' will be done purely through the Employee entity - adding to the IList property. IE: I want to quite simply be able to do the following;
Employee e = new Employee();
e.Name = "Tony";
e.StatusList.Add( new EmployeeStatus("Status A") );
e.StatusList.Add( new EmployeeStatus("Status B") );
session.Save(e);
I've tried various methods, including creating a one way one-to-many mapping where inverse is false, cascade set to all-delete-orphan, which all looks like it should work, but it generates an exception about being unable to set the EmployeeId in EmployeeStatus. I'm led to believe that this is because NHibernate wants to do an insert with EmployeeId as NULL and then update it to the ID of the parent.
I guess I'm missing something here, so quite simply - can anyone tell me what my mapping file should look like to achieve the above?
Thanks in advance
Tony
-- edit: Heres a rough idea of the classes as requested --
public class Employee
{
private IList<EmployeeStatus> _statusList;
public Employee()
{
_statusList = new List<EmployeeStatus>();
}
public virtual int Id{ get; set; }
public virtual string Name{ get; set; }
public virtual IList<EmployeeStatus> StatusList
{
get
{
return _statusList;
}
}
}
public class EmployeeStatus
{
public virtual int Id{ get; set; }
public virtual string StatusText{ get; set; }
public EmployeeStatus()
{
}
public EmployeeStatus(string statusText)
{
StatusText = statusText;
}
}
The scenario you've described is just a basic one-to-many mapping. Here is the Fluent NHibernate mapping for this:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
WithTable("Employee");
HasMany(employee => employee.StatusList)
.Cascade.All();
}
}
You do not need to maintain a reference from EmployeeStatus back to Employee to achieve this.
Turns out that what I want to do isn't possible - you have to have a bi-directional association, and must set the child's parent reference. Not a massive problem I suppose, but didn't want to hold references in the child that I don't need within my code directly.
I may not of explained clearly, but an employee status cannot be linked to more than one employee. It's definitely 1 (employee) to many (status')
In the physical database, the status entity has an employeeID field, which isn't in the domain - IE: I hold no reference back to employee from the status entity, but the physical field should be inferred from the owner of the collection - In fact, it does do this if I set the EmployeeID field in the status table to nullable - it actually executes 2 SQL statements - an insert and then an update, the EmployeeID being set in the update.
Thanks,
Tony
Can you post the code for the classes?
Are you trying to keep a history of statuses for an Employee?
-- Edit --
Looks like you are going to need many-to-many, since the child in the relationship (EmployeeStatus) has no reference back to the parent (Employee).
-- Edit 2 --
If you want the insert to be done as 1 call to the DB, you are going to need to add an Employee property to the EmployeeStatus class, and set the Inverse=true. And I'm pretty sure that you are going to need to add some logic which sets the bi-directional relationship in the objects. I.E.
public void AddStatus(EmployeeStatus status)
{
this.StatusList.Add(status);
status.Employee = this;
}