How to create NHibernate HasManyToMany relation
Asked Answered
T

1

1

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:

enter image description here

Trellas answered 15/1, 2014 at 11:7 Comment(2)
do you want to use same address table for both person and company?Jacki
yes. it will contain all the addresses but shared table will contains which company is using under the which description. Like companyAddreses table I will create PersonAddresses table.Trellas
B
2

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:

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...

Burseraceous answered 15/1, 2014 at 11:22 Comment(4)
Think about class, student, enrollment. There are classes and students. A student can enroll to many classes. How would you design without making HasManyToMany. I have companies, peoples and addresses, some people has more than 1 address and some of them may stay at the same address.Trellas
I extended the answer with an example. I am using this approach for years... and it brings lot of advantages. Objects are light, no exotic mapping with hidden tables. We can extend the pairing table/entity.. we can do subqueries... The cascading in this case, used on HasMany would properly store the pairing object...Foretooth
@RadimKöhler Is adding references in AdressCompanyMap is necessary.Sweeny
I would say YES. Unless you are talking about automaping? I just wanted to explain that the AdressCompany do have these references... If we are talking about conventions... then of course, lot of code, thanks to fluent stuff could be not used... But the essenec here is, that with the pairing object we do gain the freedom ;)Foretooth

© 2022 - 2024 — McMap. All rights reserved.