I'm having bit complicated object model that forms a triangle. There is User
entity that has collections of Items
and Taxonomies
. Item
has a taxonomy, too. And for convenience, I wanted Item
and Taxonomy
to know its owner and Taxonomy
to know its Item
, if any. See diagram:
So this makes three bi-directional relations. My problem is when I map it in NHibernate like that and asking for user with given ID, I'm getting Select N+1 problem.
At first, User
is loaded with eagerly fetched Items
. Then Taxonomies
are loaded with eagerly fetched Item
connected to it. And this is as expected and as defined in mappings. But now there is N+1 queries to load Items
related with Taxonomies
.
This is redundant as all parts of object graph was already loaded. Thie problem disappears when I make my User-Item
relation unidirectional from User
side (there are only 2 queries, as expected), but I don't want to remove that backward relationship. Is it possible to have optimal fetching with all three relations bidirectional?
Here are my mapping parts:
public class UserOverride : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
mapping.HasMany(x => x.Items).Inverse()
.Not.LazyLoad().Fetch.Join();
mapping.HasMany(x => x.Taxonomies).Inverse()
.LazyLoad().Fetch.Select();
}
}
public class ItemOverride : IAutoMappingOverride<Item>
{
public void Override(AutoMapping<Item> mapping)
{
mapping.References(x => x.Taxonomy); // many-to-one
}
}
public class TaxonomyOverride : IAutoMappingOverride<Taxonomy>
{
public void Override(AutoMapping<Taxonomy> mapping)
{
mapping.HasOne(x => x.Item).PropertyRef(x => x.Taxonomy)
.Not.LazyLoad().Fetch.Join();
}
}
And I query my database the simplest possible way:
var user = session.Get<User>(1);