How to create NHibernate HasManyToMany relation

2020-01-26 12:30发布

问题:

I know there are questions about HasManyToMany but this time I want to put couple fields into middle table like 'Description, CreationDate'.

For my situation I don't want to bind two way. I have company, person and address tables. And every company or person may have more than 1 address. In this situation what should I do? How should I write the code of classes and mappings?

Below you can see the tables:

回答1:

In this case the answer is pretty simple. Do not use many-to-many. Use pairing object. Exactly for the reasons you've mentioned: Extend the pairing object with more properties:

Check here 24. Best Practices, a cite:

Don't use exotic association mappings.

Good usecases for a real many-to-many associations are rare. Most of the time you need additional information stored in the "link table". In this case, it is much better to use two one-to-many associations to an intermediate link class. In fact, we think that most associations are one-to-many and many-to-one, you should be careful when using any other association style and ask yourself if it is really neccessary.

Other words, create the one-to-many relations refering the pairing objects from boht ends, and many-to-one from the pairing object.

Also check these:

  • Hibernate: many-to-many relationship table as entity
  • NHibernate Bidirectional Many-to-Many Mapping List / Bag
  • Nhibernate: How to represent Many-To-Many relationships with One-to-Many relationships?

An example of the Address and Company. First Pairing object

public class AddressCompany
{
    // the relation to both sides
    public virtual Address Address { get; set; }
    public virtual Company Company { get; set; }

    // many other settings we need
    public virtual string   Description  { get; set; }
    public virtual DateTime CreationDate { get; set; }
    ...
}

the Address and Company in a nut-shell:

public class Address
{
    public virtual IList<AddressCompany> Companies { get; set; }
    ...
}

public class Company
{
    public virtual IList<AddressCompany> Addresses { get; set; }
    ...
}

The mapping is as expected:

public AddressMap()
{
    HasMany(x => x.Companies)
     ...
}
public CompanyMap()
{
    HasMany(x => x.Addresses)
     ...
}
public AddressCompanyMap()
{
    References(x => x.Address)..
    References(x => x.Company)..
     ...
}

So, this is representing the Pairing object

Well, but now we can find some Companies Created after a date:

var subquery = QueryOver.Of<AddressCompany>()
    .Where(c => c.CreationDate > new DateTime(2000, 1, 1))
    .Select(c => c.Company.ID);

var query = session.QueryOver<Company>()
    .WithSubquery
    .WhereProperty(c => c.ID)
    .In(subquery)
    ...;

This way we can also filter Company over the Address...