NHibernate how do you map a crossreference table t

2019-03-01 06:06发布

问题:

I have recently inherited a project at work that contains NHibernate. I am extremely new to it and have to make a modification to one of the mappings. I've read through the documentation here and I'm still not sure how to do this or if my understanding/terminology is even correct.

So given the following table structure I need a bag that will get me the ProjectName:

User
  UserID (PK)

ProjectUser
  UserID (PK, FK User.UserID)
  ProjectID (PK, FK Project.ProjectID)

Project
  ProjectID (PK)
  ProjectName

Here is the existing bag mapping and it correctly returns the ProjectID, but now I'm trying to understand how I need to modify it to return both the ProjectID and the ProjectName:

<bag name="Projects" table="ProjectUser" lazy="true" inverse="true" cascade="save-update">
  <key column="UserId"></key>
  <many-to-many class="Project" column="ProjectID"></many-to-many>
</bag>

回答1:

Well, your mapping seems to be correct, i.e. already returning the ProjectName. To be sure please, check that the object Project is mapped like this:

<class name="Project" table="Project">
  <id name="Id" column="ProjectID" generator class="native"/> 

  <!-- above as the Id we have mapping for column ProjectId
        below the C# Name will contain the column ProjectName -->

  <property name="Name" column="ProjectName" />

  <!-- related Users to this Project -->
  <bag name="Users" table="ProjectUser" lazy="true" >
    <key column="ProjectID"></key>
    <many-to-many class="User" column="UserID" />
  </bag>

</class>

And the Project would be like this

public class Project 
{
    public virtual int Id { get; set;}
    public virtual string Name { get; set;}
    public virtual IList<User> Users { get; set;}
    ...

So, having this in place, we should be able to use the User:

public class User 
{
    public virtual IList<Project> Projects { get; set;}
    ...

mapped and loaded by NHibernate like this

user = session.Get<User>(x) // id of searched user

foreach(var project in user.Projects)
{
  var name = project.Name;
  var id = project.Id;
  ...
}

NOTES:

In case of many-to-many there obviously could/should be <bag> mapping on both sides - Project and User. But only one of them can have inverse="true". So in this case Project.Users does not have that.

The cascade setting on many-to-many is doing (most likely) different thing than one would expect. It is not related to the pairing table but to the second end of that mapping.

Cascading of the pairing object is done out of the box. It does not have to be mapped, in fact it cannot be mapped or turned off... Other words I would suggest to remove that cascade, unless you really want to change the Project in persistence, if you are working with some User.

Check also:

  • 23.2. Author/Work
  • How to do it without many-to-many ... with explicit pairing object as a mapped Entity: Nhibernate: How to represent Many-To-Many relationships with One-to-Many relationships? or Am I doing many to many incorrectly when using fluent nhibernate?