I have such domain structure (example, pseudo code):
class Room
{
Id: long
Shelves: list of Shelf
}
class Shelf
{
Id: long
Room: Room class (room_id column)
Books: list of Book
}
class Book
{
Id: long (id column)
Shelf: Shelf class (shelf_id column)
Room: Room class (room_id column)
Title: string (title column)
}
Every collection is lazy.
I'd like to know is there a way to fetch all books for a room (without subselect) when I access a Shelf's Books property in lazy manner.
When I get Room, nhibernate fetches only room (select * from rooms r where ...), when I access Shelves property, nhibernate fetches all shelves for this room (select * from shelves s where s.room_id = X), when I access Books property it loads books for the only one shelf (what is normal in general), but...
In my case if I access Book, there is high probability that I will work with other books of this room too, so if I touch book I want to preload all books for this room and put them on theirs shelves.
The most closest feature of nhibernate is fetch='subselect'. But there is unnecessary select in my case because I can fetch books for this room by room_id: select * from books b where b.room_id = x.
Is there a way to do this?
Thanks!
The native way built into NHibernate is called Batch Fetching:
19.1.5. Using batch fetching
NHibernate can make efficient use of batch fetching, that is, NHibernate can load several uninitialized proxies if one proxy is accessed (or collections. Batch fetching is an optimization of the lazy select fetching strategy. There are two ways you can tune batch fetching: on the class and the collection level.
More details (except the doc link above) could be found here:
How to Eager Load Associations without duplication in NHibernate?
NHibernate Fetch/FetchMany duplication in resultset, how to fix with ToFuture()
How to eager load objects in a list/collection?
I've found a more elegant solution. It turns out I can define sql-query for a bag/map...
It looks like:
<hibernate-mapping...>
<class name="Shelf">
<many-to-one name="Room" column="room_id"... />
<bag name="Books">
...
<loader query-ref="ShelvesQuery" />
</bag>
</class>
<sql-query name="ShelvesQuery">
<load-collection alias="book" role="Shelf.Books" />
<![CDATA[
select b.id
b.room_id,
b.shelf_id,
b.title
from books b
where b.room_id = :room_id
]]>
</sql-query>
</hibernate-mapping>
It works like a charm!
Related
We have a situation where we are trying to retrieve a couple of levels deep for an object graph using QueryOver. So if our top level is ParentEntity and our children are ChildEntitysA, ChildEntitysB and ChildEntitysC then we have something like the following code to retrieve our graph.
var query = session.QueryOver<ParentEntity>(() => pAlias).Where(() => pAlias.Id == key).Future<ParentEntity>();
var queryA = session.QueryOver<ParentEntity>(() => pAlias).Left.JoinAlias(x => x.ChildEntitysA, () => caAlias).Where(() => pAlias.Id == key).Future<ParentEntity>();
var queryB = session.QueryOver<ParentEntity>(() => pAlias).Left.JoinAlias(x => x.ChildEntitysB, () => cbAlias).Where(() => pAlias.Id == key).Future<ParentEntity>();
var queryC = session.QueryOver<ParentEntity>(() => pAlias).Left.JoinAlias(x => x.ChildEntitysC, () => ccAlias).Where(() => pAlias.Id == key).Future<ParentEntity>();
return query.ToList();
This should generate 4 SQL statements in one single call to the database and brings back what we want. However, the SQL it generates does have some inefficiency as all of the child queries will contain in the SELECT statement all the columns of the parent as well as the child entity's columns, something akin to:
SELECT parent.col0, parent.col1, parent.col2, parent.col3, .... parent.col99
FROM parent WHERE .....
SELECT parent.col0, parent.col1, parent.col2, parent.col3, .... parent.col99, childA.col0, childA.col1, childA.col2 .... childA.col99
FROM parent LEFT OUTER JOIN childA ON ....
SELECT parent.col0, parent.col1, parent.col2, parent.col3, .... parent.col99, childB.col0, childB.col1, childB.col2 .... childB.col99
FROM parent LEFT OUTER JOIN childB ON ....
SELECT parent.col0, parent.col1, parent.col2, parent.col3, .... parent.col99, childC.col0, childC.col1, childC.col2 .... childC.col99
FROM parent LEFT OUTER JOIN childC ON ....
yet the query generated for the parent entity already contains all the necessary data! This does become a bit of an efficiency concern if we're returning multiples of the parent and the volume of data per child query rises accordingly (especially as the entities involved are quite large in terms of the number of underlying columns).
So, is there any way we can force nHibernate to not generate SQL to return all the parent entity's values for every single part of the query and just limit it to returning minimal key columns only in the SQL? Is Queryover even the optimal API for this situation?
The way I would suggest, is to use full power of NHibernate features in these combinations:
The first is a complex query.
The second is to profit from lazy loading and batch-size setting
So, in the first case we are about to create one and only one QueryOver (maybe including some subqueries)
It must contain projections, that's essential. it can include (many) Left, Inner joins, can be deeply filtered... We will then get the narrowed SELECT statement, containing only required fields. This results in one SQL query, which must be converted into some (unmapped) DTO object
The Projections and DTO means, that at the end we have to use ResultTransformer, which will convert all coming selected fields into DTO object properties.
In the second case, we are trying to profit from lazy behaviour and batch-size mapping. It could look like this:
1) class/ entity
<class name="ParentEntity" batch-size="25" lazy="true">
...
2) collection
<bag name="Children" lazy="true" batch-size="25"
...
See more in documentation: 19.1.5. Using batch fetching
What we gain here is, that we can create soft queries returning only light objects (these which were mapped). This is the first Select. Then all the properties (many-to-one, one-to-many) are loaded in batches - but only if they are accessed, needed.
This leads to more than 1 SELECT clause, but also there is no inflation of SELECT clauses like 1 + N. If NHibernate will find out, that some of the required properties is already loaded in the session... it won't fire the SELECT any more.
Summary: both approaches are really the way. Try to play arround to find out in which situation you get more from the first or the second. BUT the mapping with lazy="true" and batch-size="25" should be used anyway
Some more links about batch-size:
How to Eager Load Associations without duplication in NHibernate?
NHibernate QueryOver with Fetch resulting multiple sql queries and db hits
Is this the right way to eager load child collections in NHibernate
I have this scenario:
class A
{
public virtual int Id { get; set; }
public virtual B Child { get; set; }
}
class B
{
public virtual int Id { get; set; }
}
In the mapping of class A, I have a reference to class B:
map.Reference(a => a.Child).LazyLoad();
Now when I do something like:
Session.Query<TypeOfA>().Select(a => a);
Apart from the normal select * from ATable I get n selects from the BTable for each A line. Is like lazy loading is not working.
My questions are:
How to I make the lazyload work here ?
Can I bring the A entities and B entities in a single query ?
Thank you,
Lazy loading is switched on by default and should actually work. If there would be a problem, for instance if it can't generate the proxy for class B, it would complain when creating the session factory.
Are you sure that the queries for B are done by the query itself, and not be subsequent access to A?
You could optimize the access to B in two ways: fetch them together with A in a single query. (I don't know fluent, this is the xml way to configure it:)
<many-to-one fetch="join" ...>
This has some problems when used with lists and could also blow up your query a lot. It is of course not lazy loading at all.
Another, very nice and powerful optimization is batch fetching. It allows the instances to be fetched in separate queries, but fetches several of them at once.
<class name="B" batch-size="20" ...>
This would fetch 20 B's at once in one query. It is also available for lists:
<one-to-many fetch-size="20" ...>
Expanding on Stafan's suggestion to use batch-size, a quick Google search reveals that Fluent NHibernate now supports BatchSize for queries. From the docs:
ClassMap<T> BatchSize(int size)
Sets the query batch size for this entity.
Never used it myself, and the documentation is minimal (like a lot of FNH), but maybe you can find some sample code.
Let me explain the problem - hopefully I have defined it well in the title but I want to be sure.
I have a linq query that pulls back a bunch of objects (say Foos). Each Foo holds a reference to a User. Each User holds a reference to a Person:
public class Foo
{
//properties omitted...
public User CreatedBy {get;}
}
public class User
{
//properties omitted...
public Person Person {get;set;}
}
As the object structure would suggest, in the database, Foo relates many-to-one to User, and User relates many-to-one to Person.
When I run the query, I get a single SELECT for the Foos, then a SELECT each for all the Users and People. Clearly I would much prefer a single SELECT with a couple of joins.
I don't necessarily want to specify in my mapping config that Foos ALWAYS eager fetch the User, or that Users ALWAYS eager fetch the Person, but I would like to be able to specify that in this instance.
Is there a way to do that?
Thanks
David
All the NHibernate query methods have ways of specifying eager fetching.
For Criteria, you have SetFetchMode.
For HQL, you have [inner|left] join fetch.
For Linq yo have Expand (2.x contrib) / Fetch (3.x).
For SQL you have AddJoin.
Both Udi Dahan and Ritesh Rao offer example implementations of dynamic fetching strategies for NHibernate, this should give you a good starting point.
Additionally to Diegos nice answer: You can also use batching. This reduces the N+1 problem without much pain:
use batch-size on class level:
<class name="Person" batch-size="20">
...
</class>
use batch-size on collection level:
<map
name="SomeCollection"
batch-size="20">
...
</map>
When ever one of these references is loaded, NHibernate loads 20 at once using a query like this:
select ... from Person where user_fk in (23, 34, 6, 667, 6745, 234 ....)
So it turns N+1 to N / 20 + 1, which is pretty good.
I have two associated business objects - A and B.
the association is (A->B)many-to-one, with B.Id a foreign key in A (so A has A.B_id in the DB).
I'm using lazy=true and solved most of my problems,
however in A's ToString I want to print also A.B.Id, which I should have without further trips to the DB. but accessing A.B activates the proxy, and since this isn't in the context of an open session, throws an exception.
one easy but ugly solution would be to have A.B_id property. but that's part of the stuff we were trying to avoid in the first place.
any "organic" way to do this? :)
thanks!
UPDATE: just read about caching and Session.Get vs. Session.Load. before I only new that one throws an exception if the object doesn't exist (Session.Load), and the other returns a null object (Session.Get). after reading about caching here, it's clear that Session.Load returns a proxy to the object, and only lazily fetches it when a property other than the ID is accessed, which is very much like what I need from associations!
for now I added the separate object ids (added B_Id to A so I can access it as A.B_Id instead of using A.B.Id)
If you are using NHibernate 3.2 or later, you could use the following code to get the id of associated object without another roundtrip to database to load the whole object:
using NHibernate.Proxy;
...
object id = null;
if (obj.IsProxy()) // obj is the object you want to get its identifier.
{
var proxy = obj as INHibernateProxy;
if (proxy != null)
{
var li = proxy.HibernateLazyInitializer;
if (li != null)
id = li.Identifier;
}
}
For the exact same reason I have used explicit A.B-ID properties for all my many-to-one relationships. I do not see this as a quick and dirty solution as it provides a solution to this problem and also lot of flexibility is the saving-updating area i.e. I do not need to fetch from the database the B object just to assign it to A in order to create the association when I have the B_ID in a query string or somewhere else.
My mapping files useually look like this:
<property name="CreatorID" column="CreatorID" type="Int32" not-null="true" />
<many-to-one name="Creator" column="CreatorID" class="SystemUser" insert="false" update="false" cascade="none" />
As you can see one of the 2 properties has to be read only to avoid having NHibernate sending 2 times this column to the database when inserts or updatas are happening. The above makes as read only (by using the insert="false" update="false" attributes) the many-to-one but you can instead have as read only the CreatorID property if you like.
Having only the many-to-one you do not have a property in your entity class A to hold the B.ID value. The only way to get it is by accessing the B object which will trigger the proxy and it will fire a query to the database (if it is not loaded in the session already).
I will be happy to hear any other option that provides a solution and offers the same kind of flexibility.
You can use GetIdentifier method of Nhibernate session :
session.GetIdentifier(obj);
NHibernate noob here. Looking for advice on how to map the following common scenario:
[Store]
id pk
Name
[StockItem]
id pk
Name
[StockItemStore]
id pk
StockItemId fk
StoreId fk
ParLevel
I have created a domainmodel that allows various StockItems to be assigned to various Stores via the StockItem Entity using a AssignToStore(Store store) method.
I am now using nhibernate to create my db schema. How do I setup the mapping files for this basic scenario?
Any tips greatly appreciated.
Chev
Unfortunately this relationship isn't the easiest thing to model in nHibernate and there are some inherent problems you will encounter when trying to do queries on the data in the linking table, that will require some complicated workarounds, but once you get it set up it works quite well.
My approach to this is to set it up as two many-to-one mappings with the following relationship in the Store mapping and the inverse relationship in the StockItem mapping.
<bag name="StockItems" table="StockItemStore" lazy="true">
<key column="StoreId" />
<composite-element class="SuperStore.Components.StockItemStore, SuperStore.Components">
<property name="ParLevel" type="Int32" />
<many-to-one name="StockItem" column="StockItemId" class="SuperStore.Components.StockItem, SuperStore.Components" fetch="join" cascade="all" />
</composite-element>
</bag>
the Store class will have the following collection:
public virtual IList< StockItemStore > StockItems {get;set;}
and StockItem will have the inverse again:
public virtual IList< StockItemStore > Stores {get;set;}
The StockItemStore object is able to contain either object (Store or StockItem) and any additional information that is in the linking table. (in this case just the ParLevel.
depending on which side you are looking at the StockItemStore object from either Store or StockItem will null. It could be broken out into two classes, but I find this approach easier to work with. It just requires you as the developer to know which side you are approaching it from, but its a good tradeoff for making the code simpler and more reusable in my opinion
public class StockItemStore
{
private StockItem stockItem;
private Store store;
public virtual StockItem StockItem
{
get
{
if (stockItem == null)
{
stockItem = new StockItem();
}
return stockItem;
}
set
{
stockItem = value;
}
}
public virtual Store store
{
get
{
if (store == null)
{
store = new Store();
}
return store;
}
set
{
store = value;
}
}
public virtual int ParLevel { get; set; }
}
My approach doesn't use the single unique identifier in the StockItemStore as you defined in your question, but rather what amounts to a composite key in the linking table. But it has served me well in the past overall. I'm sure you could shoehorn that id in somehow if you really needed it.
This approach works great for querying using HQL. if you are trying to use ICriteria queries it tends to get a little wonky. There are some solutions out there with using database views to simulate another table to use for querying that have worked for me.
If you need to do ICriteria queries let me know and I can post some sample code.
Max
I would strongly recommend reading up on nHibernate. Here's a very good starting point:
The nHibernate FAQ
I would also recommend that you do the mappings by hand the first couple of times. After that, you should check out Fluent nHibernate. Fluent nHibernate can (among other things) automatically generate the mappings for you from your domain model and also help you to generate the database schema. It is a very flexible tool that is getting better and better. You'll find it here:
Fluent nHibernate
Good luck!