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.
Related
I have following class:
public class PurchaseOrder
{
...
Store Store { get; protected set; }
User CreatedBy { get; protected set; }
User ApprovedBy { get; protected set; }
...
}
User and Store classes are mapped with lazy="false" option.
<class name="User" lazy="false">
More to say them associated to some other entities that mapped with lazy="false" option. And I am not allowed to change it. It's not "my" classes, them belongs to other domains.
My problem that every time that I fetch PurchaseOrder it produces additional queries for those classes and their dependencies leading me to SELECT N+1 problem. In 99% of cases I do not need all that information - store id and user id is enough for me.
Tried to use ...
session.CreateCreteria<PurchaseOrder>()
...
.SetFetchMode("CreatedBy", FetchMode.Lazy)
.SetFetchMode("ApprovedBy", FetchMode.Lazy)
.SetFetchMode("Store", FetchMode.Lazy)
...
.. but it does not help.
How can I force those associations to be lazy and to ignore lazy="false"?
Just to be clear. The information that stored in User and Store classes is useless for my domain. So I do not want it to be fetched at all. Also if I join users and stores in my query it will lead to chain of queries for entities that also mapped as lazy="false" (do not ask why, I can't change it). I aligned to some company's standard and must reference those classes (I do not like it but this is a rule), but I do not want to fetch their data, i want it lazy.
You can't override lazy="false".
What you can do is the exact oposite of what you did: fetch eagerly (FetchMode.Eager or FetchMode.Join, which are synonyms).
I've got complex entity with a lot of children collection of objects, which are complex too:
public class Order : AdvancedBaseOrder, ICheckable
{
public virtual ICollection<RouteUnit> RouteUnits
public virtual ICollection<Invoice> Invoices
public virtual ICollection<Call> Calls;
public virtual ICollection<Payment> Payments;
......
}
My payment class aggregates a lot of other objects
public class Payment: ICheckable
{
public virtual A A;
public virtual B B;
public virtual C C;
public virtual D D;
......
}
I want get order with 2 queries:
load order entity without payments (FetchMode.Lazy)
load payments by order with joining its objects
combine\merger order with its payments
I don't want lazy load payments by nhib, cause I would like override fetch strategies for payment's objects.
So my question is how can i merge combine two result of queries in one aggregate
. Thanks
In this case, batch-size="25" setting could do the job for you. Read more in the documentation: 19.1.5. Using batch fetching.
batch size coulde be applied on a class or collection maping:
Payment class
<class name="Payment" batch-size="10">...</class>
Collection of Payments
<class name="Order">
<set name="Payments" batch-size="3">
...
</set>
</class>
How the batching works in a nutshell: NHibernates loads the set of all Orders. Then based on a batch-size setting (e.g. 25) creates few calls to Payments filtered by IDs of just loaded Orders:
WHERE OrderId in (#o1, #o2, #O3... #o25)
The merge will be done for you inside NHibernate session. From my experience this is most powerful mapping... Lazy & Batching.
I am looking for some way to dynamically map database tables classes in my application using nhibernate (or if some other ORM works then let me know). I am fairly new to nhibernate, I used entity frameworks in the past though.
Most of my application will be using a static structures and fluent nhibernate to map them.
However there are multiple database tables that will be needed to be created and mapped to objects at each install site. These will all have as a base structure (id,name etc) however they will have additional fields depending on the type of data they are capturing. From some reading I found that I can use the "dynamic-component" mapping in xml to add fields using an IDictionary Attributes property. This is the first step and seems relatively straight forward. Ref (http://ayende.com/blog/3942/nhibernate-mapping-dynamic-component)
The second step is where I am struggling. I will need to define tables and map them depending on the client’s need. As stated above each of the tables will have a set of static properties, and some dynamic ones. They will also need to reference a static “Location”Class as shown below
Location (STATIC) (id,coordinates)
-----DynamicTable1 (DYNAMIC) (id,Name,location_id, DynamicAttribute1, DynamicAttribute2........)
-----DynamicTable2 (DYNAMIC) (id,Name,location_id, DynamicAttributeA, DynamicAttributeB....)
We will need to be able to create / map as many of these DynamicTables as the client needs. DynamicTable1, DynamicTable2 etc will most likely be different in some ways for most client sites. Is there any way in nhibernate to achieve this? The creating / management of the tables in the Database will be managed elsewhere, I just need some way to get this to map in my ORM.
A bit of background
This application will be used to store geological data. As geological data is inherently different depending on where it is, and geologist are using different methods and looking for different elements (gold, coal etc), the data structure to store this information needs to be extremely flexible.
Take a look at the new Mapping By Code functionality of NH 3.2. It should make it easy to create new table definitions at runtime. In contrast to Fluent, you don't need to write a mapping class, you just can add new classes in for loops:
// lookup all dynamic tables in the database using SQL or SMO or whatever
var dynamicTables = GetDynamicTables();
// map all dynamic tables
foreach(var table in dynamicTables)
{
mapper.Class<MyGenericEntity>(ca =>
{
// use an entity name to distinguish the mappings.
ca.EntityName(table.Name);
ca.Id(x => x.Id, map =>
{
map.Column("Id");
map.Generator(Generators.HighLow, gmap => gmap.Params(new { max_low = 100 }));
});
// map properties, using what ever is required: if's, for's ...
ca.Property(x => x.Something, map => map.Length(150));
});
}
Using the entity name you can store and load the entities to and from different tables, even if they are mapped as the same entity class. It is like Duck Typing With NHibernate..
Believe me, it won't be easy. If you are interested in a big challenge which impresses every NH expert, just go for it. If you just want to get it working you should choose a more classic way: create a static database model which is able to store dynamic data in a generic way (say: name value pairs).
see answer in Using nNHibernate with Emitted Code
class DynamicClass
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Location Location { get; set; }
public virtual IDictionary DynamicData { get; set; }
}
Template
<hibernate-mapping>
<class name="DynamicClass">
...
<dynamic-component name="DynamicData">
<!--placeholder -->
</dynamic-component>
</class>
</hibernate-mapping>
replace <!--placeholder --> with generated
<property
name="P1"
type="int" />
<property
name="P2"
type="string" />
configure Sessionfactory
var sessionFactory = new NHibernate.Cfg.Configuration()
.AddXml(generatedXml)
... // DatabaseIntegration and other mappings
.BuildSessionFactory();
Query
var query = session.CreateCriteria<DynamicClass>();
foreach (var restriction in restrictions)
{
query.Add(Restrictions.Eq(restriction.Name, restriction.Value))
}
var objects = query.List<DynamicClass>();
Edit: ups i havent realised you need multiple tables per client
Option 1:
<class name="DynamicClass" table="tablenameplaceholder"> with replace and a different Sessionfactory for each dynamic class
Option 2:
Subclassing the dynamic class and use TPS (table per subclass) mappings
Option 3: see Stefans answer just with xml
<class name="DynamicTable1" class="DynamicClass" table="DynamicTable1">
I'm just trying to get my head around nHibernate and have a query. When setting up the mappings file (with Fluent or regular .hbm.xml files) you specify relationships (bags; one-to-many, etc) and sub-types - the idea being (I believe) is that when you fetch an object it also fetches and matching data. My question is can I programmatically tell my query to ignore that relationship?
So, below, there is a Foo class with a list of Bar objects. Within the mappings file this would be a one-to-many relationship and sometimes I want to retrieve a Foo with all Bars BUT sometimes I want to just retrieve the Foo object without the Bar, for performance reasons. How can I do this?
public class Foo { public int Id { get; set; } public List<Bar> { get; set; } }
public class Bar { public int Id { get; set; }
Cheers
The relationship shouldn't be loaded automatically unless you turn off Lazy Loading or specify it to be eager loaded in the query.
Edit:
To answer your questions in the comment below.
1) It's done as part of the query. An basic example using QueryOver in NHibernate 3.0 would look something like:
var result = Session.QueryOver()
.Fetch(x => x.Category).Eager
.Where(x => x.Price > 10)
.List();
I think with ICriteria it's "SetFetchMode("Category", FetchMode.Eager)"
2) If you turn off lazy-loading on the mapping for an object, it will effectively always be eager loaded. Tho I suggest you eager load on a query-by-query basis to avoid the possibility of having a massive chain of data loaded, or loading data you don't actually need.
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!