Fluent NHibernate one-to-many with intervening join table? - nhibernate

I'm having trouble getting the Fluent Nhibernate Automapper to create what I want. I have two entities, with a one-to-many relationship between them.
class Person
{
public string name;
IList<departments> worksIn;
}
class Department
{
public string name;
}
The above is obviously bare bones, but I would be expecting to generate the fleshed out schema of:
Person{id, name}
Department{id, name}
PersonDepartment{id(FK person), id(Fk Department)}
Unfortunately, I am instead getting:
Person{id, name}
Department{id, name, personid(FK)}
I don't want the FK for Person included on the department table, I want a separate join/lookup table (PersonDepartment above) which contains the primarykeys of both tables as a composite PK and also Fks.
I'm not sure if I am drawing up my initial classes wrong (perhaps should just be LIst workIn - representing ids, rather than List worksIn), or if I need to manually map this?
Can this be done?

The way the classes have been structured suggests a one-to-many relationship (and indeed that's how you describe it in your question), so it should not be a surprise that FNH opts to model the database relationship in that way.
It would be possible, as you suggest, to manually create a many-to-many table mapping. But, is this definitely what you want?
I tend to find that pure many-to-many relationships are quite rare, and there is usually a good case for introducing an intermediate entity and using two one-to-many relationships. This leaves open the possibility of adding extra information to the link (e.g. a person's "primary" department, or perhaps details of their office within each of their departments).
Some example "bare-bones" classes illustrating this kind of structure:
public class Person
{
public int Id { get; set;}
public string Name { get; set;}
public IList<PersonDepartment> Departments { get; set; }
}
public class PersonDepartment
{
public int Id { get; set; }
public Person Person { get; set; }
public Department Department { get; set; }
public bool IsPrimary { get; set; }
public string Office { get; set; }
}
public class Department
{
public int Id { get; set; }
public IList<PersonDepartment> Personnel { get; set; }
public string Name { get; set; }
}

Related

One-to-one entity framework

I am doing the entity framework code first to set up my database.
I have two classes where their relationships are one-to-one, Lecturer & LoginInfo.
public class Lecturer
{
public int LecturerId { get; set; }
public string FullName { get; set; }
public int UserId { get; set; }
public LoginInfo LoginInfo { get; set; }
}
public class LoginInfo
{
public int UserId { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public bool ChangePassword { get; set; }
public Lecturer Lecturer { get; set; }
}
So for my entity framework, I have written this for the one-to-one relationship.
modelBuilder.Entity<Lecturer>()
.HasOne(input => input.LoginInfo)
.WithOne(input => input.Lecturer)
.HasForeignKey<Lecturer>(input => input.UserId);
From the code above, does it mean that Lecture has one LoginInfo, LoginInfo with one Lecturer and Lecturer has a UserId as a foreign key?
Another question would be, for this one to one relationship, do I have to write another set of code for LoginInfo like this:
modelBuilder.Entity<LoginInfo>()
.HasOne(input => input.Lecturer)
.WithOne(input => input.LoginInfo)
.HasForeignKey<LoginInfo>(input => input.LecturerId);
I am just a beginner trying to learn, thanks for helping :).
From the code above, does it mean that Lecture has one LoginInfo, LoginInfo with one Lecturer and Lecturer has a UserId as a foreign key?
Correct. It also means that LoginInfo is the principal and Lecturer is the dependent end of the relationship. Also since the FK property is not nullable, the relationship is required, i.e. in order to create Lecturer you have to create LoginInfo first, which is not associated with another Lecturer.
Also note that since the UserId is not following the default convention for PK name, you should explicitly configure it as PK of the LoginInfo:
modelBuilder.Entity<LoginInfo>()
.HasKey(e => e.UserId);
Another question would be, for this one to one relationship, do I have to write another set of code for LoginInfo like this
No. Single relationship requires single configuration and single FK. If you do so, you would be defining a second relationship, which also would create circular dependency between the entity, which should be avoided in general. The first fluent configuration fully defines the desired relationship and is enough to handle loading related data and other CRUD operations.
For more info about terms, relationship types and configuration, see Relationships section of the EF Core documentation.

Fluent Nhibernate Cascade.None() results in HasOne foreign key relationship not being persisted

I'm having issues with Nhibernate persisting a HasOne Relationship for one of my entities with Cascade.None() in effect. My domain model involves 4 classes listed below.
public class Project
{
public virtual int Id {get;set;}
public virtual IList<ProjectRole> Team { get; protected set; }
}
public class ProjectRole
{
public virtual int Id { get; set; }
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
public class Role
{
public virtual int Id { get; set; }
public virtual string Value { get; set; }
}
public class User
{
public virtual int Id { get; protected set; }
public virtual string LoginName { get; set; }
}
So basically we have projects, which have a list of ProjectRoles available from the Team property. Each ProjectRole links a User to the specific Role they play on that project.
I'm trying to setup the following cascade relationships for these entities.
project.HasMany<ProjectRoles>(p=> p.Team).Cascade.All()
projectRole.HasOne<Role>(r => r.Role).Cascade.None()
projectRole.HasOne<User>(r => r.User).Cascade.SaveUpdate()
I've used fluent nhibernate overrides to setup the cascades as above, but I'm finding that the line
projectRole.HasOne<Role>(r => r.Role).Cascade.None()
is resulting in the ProjectRole.Role property not being saved to the database. I've diagnosed this be looking at the SQL Generated by Nhibernate and I can see that the "Role_id" column in the ProjectRoles table is never set on update or insert.
I've also tried using
projectRole.HasOne<Role>(r => r.Role).Cascade.SaveUpdate()
but that fails as well. Unfortunately leaving it Cascade.All() is not an option as that results in the system deleting the Role objects when I try to delete a project role.
Any idea how to setup Cascade.None() for the ProjectRole-> Role relationship with out breaking persistence.
HasOne is for a one-to-one relationship which are rare. You want to use References to declare the one side of a one-to-many relationship. Making some assumptions about your domain model, the mapping should look like:
project.HasMany<ProjectRoles>(p=> p.Team).Inverse().Cascade.AllDeleteOrphan()
projectRole.References<Role>(r => r.Role);
projectRole.References<User>(r => r.User);
See also this question about the difference between HasOne and References.

Fluent Nhibernate Many to Many association to multiple classes

Fluent Nhibernate Many to Many association to multiple classes
We use Nhibernate and up to now we have been able use the auto mapping. But I think this is about to change.
We have a Code class that has a many to many relation with several other classes.
I’m thinking something along these lines:
public class Code
{
public virtual Guid Id { get; set; }
public virtual ICollection<CodeUsage> Usage { get; set; }
}
class CodeUsage
{
public virtual Guid Id { get; set; }
public virtual Code Code { get; set; }
// Class, [Property,] Id for "ANY" mapping to A & B
}
class A
{
public virtual Guid Id { get; set; }
public virtual ICollection<CodeUsage> Codes { get; set; }
}
class B
{
public virtual Guid Id { get; set; }
public virtual ICollection<CodeUsage> Codes { get; set; }
}
Many to Many will lead to the creation of a linking table, in the linking table their needs come a mapping to the classes using codes. In the documentation it is referred to as a “Any” mapping.
But I have no idea how get fluent to create one.
Thoughts anyone? or even better: a solution <);o)}{
You can't map <many-to-any> in Fluent NHibernate - it's not supported.
I think it may be a good reason to move to mapping-by-code, that supports it well.

How to use components in fluent nhibernate

I'm working on a legacy MySql database and have the following entities:
public class Company
{
public int Id { get; set;}
public string Address { get; set; }
public string City { get; set; }
}
public class CompanyDepartment
{
public int Id { get; set;}
public string Address { get; set; }
public string City { get; set; }
}
The idea is that a company only use the department class if it has more than one department.
Right now I'm trying to make a company/department search, this means I need a list of all departments and therefore I need to "create" departments of all the companies that only has one department, and therefore don't have a entry in CompaynyDepartment.
To do this I was thinking of use components in fluent NHibernate, but I'm not sure I can join the real departments with the fake ones?
Is there a better approach to this problem? It's not an option to change the database structure.
I ended up changing the database structure

Fluent Nhibernate many-to-many where table has multiple columns

I am trying to to map a many to many relationship using Fluent NHibernate.
I have a table User and a second table Organization. The association table is UserOrganization which contains the UserId and OrganizationId. The UserOrganization table also contains a few other fields (YearBegan, YearEnd).
How would I go ahead and map those using fluent mapping.
Thanks
You should probably make UserOrganization its own entity that contains those fields. That also gives you more flexibility in terms of cascading updates and deletes.
public class UserOrganization {
public virtual User User { get; set; }
public virtual Organization Organization { get; set; }
public virtual DateTime YearBegan { get; set; }
public virtual DateTime YearEnd { get; set; }
}