NHibernate - three bidirectional relations between three classes gives N+1 - nhibernate

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);

Because mappings will effect all queries, I like to live by the rule that mappings should only be changed to eagerly load if an entity is NEVER useful without an other entity. In your situation, if you ever just want Users, and could care less about the Item and the Taxonomy records, you will be doing extra database work for no benefit.
I would advise you perform the eager loading via the other route- in your query.
Session.QueryOver<User>().Where(u => u.Id == 1)
.join.QueryOver<Items>(u => u.Items)
.Join.QueryOver<Taxonomy>(i => i.Taxonomy)
.TransformUsing(Trasnformers.DistinctRootEntity);

Related

Filtering soft-deleted data with Fluent NHibernate

I'm trying to implement simple soft deletes in my application using Fluent NHibernate. All entities have a boolean flag IsDeleted, and delete operation only sets this property to true.
I'm struggling with querying more complex entities referencing each other, for example by having many-to-many relationship. Let's say I have Person entity, having a collection of Projects:
class Person : Entity {
public virtual IList<Project> Projects { get; set; }
}
class Project : Entity {
//some properties
}
Now imagine that Person p has Projects proj1 and proj2. If proj1 gets soft-deleted, we simply set its IsDeleted property to true. However, when I access p's projects, collection is automatically lazy-loaded with proj1 too, independently from its flag. Of course, I can always filter the collection, for example by Projects.Where(x => !x.Isdeleted), but this leads to repetitive code prone to bugs. I want to separate this kind of data juggling from my presentation layer.
I want to automatize this process by some global rule saying "load only entities with IsDeleted set to false", which applies to all queries and lazy-loaded collections.
What I have tried:
Override events, but I wasn't able to intercept all DB reads and filter all entities that are read.
Filters, which I couldn't get to work with lazy-loaded collections.
What would you recommend, what is the easiest way to implement soft deletes without code repetition and easily separable from presentation layer?
To complete #Rippo, off the top of my head, something like this should work:
public abstract class BaseEntity
{
public bool IsDeleted {get;set;}
}
public class SomeEntity : BaseEntity
{
....
}
public abstract class EntityMap<T>: ClassMap<T> where T:BaseEntity
{
public EntityMap()
{
Where(x=>!x.IsDeleted);
}
}
public class SomeEntityMap: EntityMap<SomeEntity>
{
...
}

Can NHibernate query for specific children without lazy loading the entire collection?

When I have an entity object with a one-to-many child collection, and I need to query for a specific child object, is there a feature or some clever pattern I haven't come up with yet to avoid that NHibernate fetches the entire child collection?
Example:
class Parent
{
public virtual int Id { get; proteced set; } // generated PK
public virtual IEnumerable<Child> Children { get; proteced set; }
}
class Child
{
public virtual int Id { get; protected set; } // generated PK
public virtual string Name { get; protected set; }
public virtual Parent Parent { get; protected set; }
}
// mapped with Fluent
class Service
{
private readonly ISessionFactory sessionFactory;
public Service(ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
void DoSomethingWithChildrenNamedBob(int parentId)
{
using(var session = sessionFactory.OpenSession())
{
var parent = session.Get<Parent>(parentId);
// Will cause lazy fetch of all children!
var childrenNamedBob = parent.Children.Where(c => c.Name == "Bob");
// do something with the children
}
}
}
I know it's not the best example because in this case one would probably just query the Child entities directly, but I have encountered situations where I already had a Parent object and needed to traverse specific sub-trees through it.
Short answer: no. Longer answer: you can make it do this, with some sleight of hand.
Rippo's answer above shows how you would do it the 'proper' NHibernate way (whether it's with Linq or QueryOver or HQL doesn't really matter - the point is you have to step outside the parent -> child relationship to do a query). You can take this a step further and disguise this behind a façade. But to do so, you have to remove the mapped relationship entirely and replace it with a query at all times. You'd take out the Parent -> Children mapping, but leave the Child -> Parent mapping intact; then re-write the property on Parent to look like this:
public virtual IQueryable<Child> Children
{
get
{
// somehow get a reference to the ISession (I use ambient context), then
return session.Query<Child>().Where(c => c.Parent == this);
}
}
Now, when you use Parent.Children you get back a queryable collection, so you could then write
IEnumerable<Child> childrenNamedBob = parent.Children.Where(c => c.Name == "Bob");
The only way you could do this and preserve the mapping is to amend NHibernate's collection objects (or inject your own). Diego Mijelshon (who is around these parts) wrote a spike of exactly that, adding IQueryable support to NHibernate collections so you could do
IEnumerable<Child> childrenNamedBob = parent.Children.AsQueryable().Where(c => c.Name == "Bob");
But from what I can see, this never went any further and there's no apparent plan to add this capability to NH. I have run Diego's code and it does work, but obviously it's not production quality and hasn't been tested, and I don't think it's ever been officially 'released' even as a private patch.
Here's the link to the discussion on the NH issue tracker: https://nhibernate.jira.com/browse/NH-2319
I believe NH should support this out of the box, as it's a natural way for most .NET devs to want to interact with pretty much anything enumerable, now that we have Linq, and not being able to do it without the side-effect of loading an unbounded collection into RAM sucks. But the traditional NH model is session -> query and that's what 99% of people use.
I asked the same question on NHusers a few weeks ago and didn't get an answer so I suspect the answer is you will always get all the parents children and then perform a in-memory filter. In many cases this might be the correct way in seeing it.
In your case I would rewrite the query to be:-
var childrenNamedBob = session.Query<Children>()
.Where(w => w.Parent.Id == parentId && w.Name == "Bob");
Then simply to get parent (if childrenNamedBob has results) you could call:-
var parent = childrenNamedBob.First().Parent;
or as you rightly pointed out:-
var parent = session.Get<Parent>(parentId);
You can now do that with NHibernate 5 directly without specific code !
See https://github.com/nhibernate/nhibernate-core/blob/master/releasenotes.txt
Build 5.0.0
=============================
** Highlights
...
* Entities collections can be queried with .AsQueryable() Linq extension without being fully loaded.
...

Map collection as Queryable

I've grown accustomed in SQLAlchemy (Python) to map a relationship/collection with lazy="dynamic" which maps the property as a Query object instead of a populated list/collection (or Proxy for lazy loaded properties). This mapped property then allows you to further refine the query used to fetch the collection before doing so (apply an order, limit, filter, etc).
For example, in SQLAlchemy I can map a relationship like so:
class Post(Base):
...
class User(Base):
...
posts = relationship(Post, lazy="dynamic")
And then when I retrieve a user, I can apply an order on posts, or only retrieve the last 5, etc.
user = session.query(User).get(1)
# Fetch the last 5 posts by user 1
posts = user.posts.order_by(Post.create_date.desc()).limit(5).all()
http://docs.sqlalchemy.org/en/rel_0_7/orm/collections.html
I would love to find a way to do this using Fluent NHibernate, mapping the collection as a QueryOver or IQueryable (LINQ) such as:
public virtual QueryOver<Post> Posts {get; set;}
or
public virtual IQueryable<Post> Posts { get; set; }
and in the mappings do something like:
public class UserMap : ClassMap<User>
{
public UserMap()
{
...
HasMany(u => u.Posts).Fetch.Dynamic
}
}
Is this currently possible using Fluent NHibernate (or just NHibernate)?
It is possible using NHibernate, however it's not quite out of the box.
You would need to write your own collectionwrapper implementing IQueryable, inject it with your own CollectionFactory and delegate the query generation to the session which loaded the containing object.

NHibernate: Map same class to multiple tables depending on parent

I have a model where multiple classes have a list of value types:
class Foo { public List<ValType> Vals; }
class Bar { public List<ValType> Vals; }
Foo and Bar are unrelated apart from that they both contain these vals. The rules for adding, removing, etc. the ValTypes are different for each class. I'd like to keep this design in my code.
There are times when I want to copy some Vals from a Foo to a Bar, for example. In the database, each ValType has its own table, to keep it small, light (it just has the parent ID + 2 fields), and allow integrity checks. I know NHibernate says I should keep my objects as granular as the database, but that just makes my code uglier.
The best I've thought of so far is to make separate subclasses of ValType, one for each parent. Then I can map those at that level. Then, I'll hook up add and remove logic to auto-convert between the right subclasses, and actually store them in a private list that has the right subclass type. But this seemed a bit convoluted.
How can I map this in NHibernate (Fluent NHibernate if possible)?
Please let me know if this is a duplicate -- I'm not quite sure how to search this.
At database level a solution would be to have:
Val(Id)
Bar(Id)
BarToVal(IdBar, IdVal)
FooToVal(IdFoo, IdVal)
I am not very sure how would these be mapped. Maybe something like:
// BarMap:
HasManyToMany(x => x.Vals).WithTableName("BarToVal");
// FooMap:
HasManyToMany(x => x.Vals).WithTableName("FooToVal");
Hope it's making sense...
You can find an example on the Google Code page for Fluent NHibernate.
Model
public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
}
Schema
table Customer (
Id int primary key
Name varchar(100)
)
table CustomerAddress (
CustomerID int,
Address varchar(100)
)
Mapping
public class CustomerMap : ClassMap<Customer>
{
public CustomerMap()
{
Id(x => x.Id);
Map(x => x.Name);
WithTable("CustomerAddress", m =>
{
m.Map(x => x.Address);
});
}
}
In this example, an entity is split across two tables in the database. These tables are joined by a one-to-one on their keys. Using the WithTable feature, you can tell NHibernate to treat these two tables as one entity.

NHibernate - Do I have to have a class to interface with a table?

I have a class called Entry. This class as a collection of strings called TopicsOfInterest. In my database, TopicsOfInterest is represented by a separate table since it is there is a one-to-many relationship between entries and their topics of interest. I'd like to use nhibernate to populate this collection, but since the table stores very little (only an entry id and a string), I was hoping I could somehow bypass the creation of a class to represent it and all that goes with (mappings, configuration, etc..)
Is this possible, and if so, how? I'm using Fluent Nhibernate, so something specific to that would be even more helpful.
public class Entry
{
private readonly IList<string> topicsOfInterest;
public Entry()
{
topicsOfInterest = new List<string>();
}
public virtual int Id { get; set; }
public virtual IEnumerable<string> TopicsOfInterest
{
get { return topicsOfInterest; }
}
}
public class EntryMapping : ClassMap<Entry>
{
public EntryMapping()
{
Id(entry => entry.Id);
HasMany(entry => entry.TopicsOfInterest)
.Table("TableName")
.AsList()
.Element("ColumnName")
.Cascade.All()
.Access.CamelCaseField();
}
}
I had a similar requirement to map a collection of floats.
I'm using Automapping to generate my entire relational model - you imply that you already have some tables, so this may not apply, unless you choose to switch to an Automapping approach.
Turns out that NHibernate will NOT Automap collections of basic types - you need an override.
See my answer to my own question How do you automap List or float[] with Fluent NHibernate?.
I've provided a lot of sample code - you should be able to substitute "string" for "float", and get it working. Note the gotchas in the explanatory text.