Fluent Nhibernate loading not falling back on lazy loading? (grandchild entities) - nhibernate

When querying nhibernate, I'm seeing some odd behavior
When I write a query like this
Repository.QueryOver<Entity>()
.Fetch(x => x.Child1).Eager
.Fetch(x => x.child2).Eager
It will eagerly grab child1 and child2 entities, but there are grandchildren for child1 and child2 that aren't lazily loaded. I'm a bit confused on how to achieve this.
In my nhibernate mappings, it seems to have no affect on the laziness or eagerness of grandchildren and I require at least some entities be eagerly loaded to avoid the N+1 query problem.
I'm also wondering how I could eagerly load grandchildren entities under my original entity.
Any help or ideas are appreciated!

I would suggest to use the batch-fetching. As discussed here, the fluent syntax is:
1) the collection setting
HasMany<MyEntity>(x => x.Entities)
.BatchSize(100);
2) the class level setting
public MyEntityMap()
{
Id(x => x....
...
BatchSize(100);
This setting should be applied on every collection and every class. To do that with fluent - we can use Conventions - see more e.g. here
'IClassConvention' - Use to alter your ClassMaps values. You can't change properties, collections, etc with this convention, only alter the settings such as Lazy and BatchSize.

Related

LINQ to NHibernate does not JOIN with subclass, whereas QueryOver does

I had this QueryOver query:
var result = session.QueryOver<TopicSelection>()
.Where(x => x.LacId == lac && x.RemoveDate == null)
.List();
In a nutshell: TopicSelection is a base class, and one subclass has many-to-one property, with lazy=false and fetch=join.
When I used QueryOver, NHibernate created nice join and fetched additional data from many-to-one table. Which is great, one query is issued and I get everything.
When I changed it to LINQ to NHibernate:
var result = session.Query<TopicSelection>()
.Where(x => x.LacId == lac && x.RemoveDate == null)
.ToList();
executed query does not contain JOIN. What is more, every time a many-to-one property is needed, an additional select is issued.
Is is a bug in LINQ in NHibernate? Can I instruct LINQ to NHibernate query to fetch data for subclass?
What you are experiencing is a "NHibernate LINQ implementation" as is today. We can effectively do two things.
In case, that we can adjust the query to ask for a subclass, or the many-to-one property is (could be) declared on base TopicSelection, we can use .Fetch()
var result = session
//.Query<TopicSelection>()
.Query<TopicSelectionSubClass>()
.Where(x => x.LacId == lac && x.RemoveDate == null)
.Fetch(x => x.Category ) // the many-to-one property joined
.ToList();
The second approach is even better. I would suggest that almost in any case. I.e. instead of any many-to-one mapping with lazy="false" fetch="join" - let's use:
19.1.5. Using batch fetching
Change the class mapping like this:
<class name="Category" batch-size="25" ...
That will change the 1+N select into 1+1 (or 1+2). Small cite from docs:
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.
Batch fetching for classes/entities is easier to understand. Imagine you have the following situation at runtime: You have 25 Cat instances loaded in an ISession, each Cat has a reference to its Owner, a Person. The Person class is mapped with a proxy, lazy="true". If you now iterate through all cats and call cat.Owner on each, NHibernate will by default execute 25 SELECT statements, to retrieve the proxied owners.
Read more here

Fluent NHibernate LazyLoad Issues

I couldn't find an answer to this issue so I assume it is something I am doing wrong.
I have a PersistenceModel set up where I have set a convention as follows: -
persistenceModel.Conventions.Add(DefaultLazy.Always());
However, for one of the HasManyToMany relationships in one of my entities I want eager loading to take place which I am setting up as follows: -
HasManyToMany(x => x.Affiliates).Not.LazyLoad();
Intuitively, I expect eager loading to take place as I am overriding the lazy load default that I have specified as a convention but it still lazy loads. If I set the DefaultLazy convention to never and then set LazyLoad on an individual relationship it doesn't work either.
Any ideas?
When you set Not.LazyLoad(), you tell NHibernate to load Affiliates when the parent loads. NHibernate will do this by performing another select on the Affliates many-to-many table regardless of whether you access the Affiliates collection or not. NHibernate is using another select because that is the default fetching mode. You want to override fetching mode as well, either in the query or in the mapping. To do it in the mapping, add the following:
HasManyToMany(x => x.Affiliates)
.Not.LazyLoad()
.Fetch.Join();
You might also want to include a ".Cascade.AllDeleteOrphan()" if you want NHibernate to persist new Affiliaites added to the collection and delete orphaned ones. If you do not do this, you will have to explicitly call session.Save(newAffiliate). Otherwise you'll receive a TransientObjectException when your Affiliates collection contains a new Affiliate.
It may be one stupid thing to ask, but have you execute the query inside your session? Say,
Using(var session = OpenSession())
{
session.Query<Entity>().ToList();
}
I had this problem before, and finally realized the objects that I was accessing hadn't been queried before disposing the session.

AutoMapper limit depth of mapping or map lazily

AutoMapper is great, saves a lot of time, but when I started looking at the performance of my application AutoMapper is responsible for performance loss.
I'm using lazy loading with NHibernate. Most of the time a need parent entity without needing to access child entities at all. In reality what happens is that AutoMapper tries to map as many relationships as possible causing NHibernate to lazy load all the child entities (I'm seeing SELECT N+1 happening all the time).
Is there way to limit how deep AutoMapper goes or is it possible for AutoMapper to map child entities lazily?
You could use the ignore method for associations you don't need to have loaded.
Mapper.CreateMap<User, UserDto>()
.ForMember(dest => dest.LazyCollection, opt => opt.Ignore())
.ForMember(dest => dest.AnotherLazyCollection, opt => opt.Ignore())
Mapper.CreateMap<UserProperty, UserPropertyDto>()
.ForMember(dest => dest.PropertyLazyReference, opt => opt.Ignore());
return Mapper.Map<User, UserDto>(user);
For associations you know you will need in your dto, you should look at ways of fetching these more efficiently with the initial query, but that is a whole new problem.
Perhaps you should consider using two different dtos; one that includes the child entities, and one that doesn't. You can then return the proper dto from your service layer depending upon the context.
I'm using pre conditions to prevent data from being mapped.
CreateMap<Team, TeamDto>()
.ForMember(dto => dto.Users, options =>
{
options.PreCondition(ctx => !ctx.Items.ContainsKey(AutoMapperItemKeys.SKIP_TEAM_USERS));
options.MapFrom(t => t.TeamUsers.Where(tu => tu.IsDeleted == false));
})
.ReverseMap();
When Map() is called I feed the Items dictionary with skip keys for the properties I don't want mapped.
this.mapper.Map<IEnumerable<Team>, IEnumerable<TeamDto>>(teams, opts =>
{
opts.Items.Add(AutoMapperItemKeys.SKIP_TEAM_USERS, true);
});
Advantages:
you can fine-grain which properties not to map
prevents from mapping to deep with nested objects
no need for duplicate dto's
no duplicate mapping profiles

How do I use Fluent Nhibernate many-to-many for optimal performance?

I have a product table that has a many-to-many relation to itself (using a two-column many-to-many table) and I have set it up in Fluent NHibernate with the following code:
public class ProductConfiguration : ClassMap<Product>
{
public ProductConfiguration()
{
Table("Product");
Id(p => p.Id).GeneratedBy.Guid();
Map(p => p.Name).Not.Nullable().Length(254);
Map(p => p.Description).Not.Nullable().Length(1000);
Map(p => p.CreatedAt).Not.Nullable();
HasManyToMany(p => p.CrossSell)
.Table("ProductCrossSell")
.ParentKeyColumn("Id")
.ChildKeyColumn("ProductId");
}
}
My MVC application has two pages that uses this setup:
Index - Uses a generic repository GetAll method to display all products.
Detail - Uses a generic repository GetById method to display one product and any related cross sell products setup in the many-to-many realation.
It looks like NHibernate is set to LazyLoad the many-to-many by default so when I fire up the application and watch it in profiler I can see that it does LazyLoad the many-to-many with the following alert "Use of implicit transactions is discouraged".
How do I get rid of this alert? I couldn't find any information on how to wrap a LazyLoad inside a transaction to get rid the alert. Is it even possible?
Is there a way to not lazyload this by telling NHibernate that whenever I ask for GetById make sure to join the tables a get everything in one query? I tried using .Fetch.Join() in the many-to-many mapping but that also affected my GetAll query which now displays a joined result set as well which is incorrect.
What is the best apprach for this kind of simple scenario?
Thanks
The way to get rid of the warning is to access the object graph and fully populate the UI elements inside a single transaction.
Not by configuration. You can create an HQL query that eager fetches the association and use that query for a specific view. I would stick with lazy loading and not make that optimization unless needed. The HQL would be:
return session.CreateQuery("from ProductionConfiguration pc join fetch pc.CrossSell where pc.Id = ?")
.SetGuid(0, id)
.List<ProductConfiguration>();
All collections are lazily loaded in NHibernate by default.
You must be triggering loading with a call of some kind (maybe even with the debugger watches)

NHibernate - Incorrect thinking? Subclassed Model based on Join

I have a simple model class (Part), which pulls from it's information from a single table (t_Part).
I would like a subclass of this model called (ProducedPart), that would still utilize NHibernate's caching mechanisms, but would only be instances of (Part) that have a foreign key relationship in a table called "t_PartProduction". I do not need to have a model for this second table.
I only need a read-only version of ProducedPart
I could always implement a Facade/Repository over this, but I was hoping to setup a mapping that would pull "t_Part" joined with "PartProduction" when I asked for "ProducedPart" in NH.
Is this the wrong way to use NH?
Edit
So, the SQL would look something like
SELECT p.*
FROM t_Part p
INNER JOIN t_PartProduction pp ON pp.PartID = p.PartID
WHERE pp.ProductionYear = '2009'
I believe what you are looking for is a joined subclass. In FNH, it will look something like:
public class PartMap : ClassMap<Part>
{
public PartMap()
{
Id(x => x.Id)
JoinedSubClass<ProducedPart>("PartID", sub => {
sub.Map(x => x.Name);
sub.Map(x => x.ProductionYear);
});
}
}
In order have NHibernate cache the results, you will need to have the subclass mapped (and if you didn't map it, you wouldn't be able to get NH to load it in the first place).
Bringing in some context from the FNH groups thread, it will not explicitly be read-only though. In my opinion, making things read-only is not an appropriate thing for NHibernate to manage. This is better controlled by the database and connections (i.e. creating a connection to the database that only has SELECT permissions on the tables/views being accessed). See my answer to a previous SO question about readonly sessions in NHibernate for more of my thoughts on the matter.
The key here is using both the where and mutable elements of the class definition for NHibernate Mappings.
Using Fluent NHibernate, this looks like:
public Part()
{
WithTable("t_Part");
Id(i => i.Id).ColumnName("PartID");
Map(m => m.Name).ColumnName("Part");
SetAttribute("where", "PartID IN ( SELECT pp.PartID FROM t_PartProduction pp WHERE pp.ProductionYear = '2009' ) ");
ReadOnly();
}
No, this is perfectly possible. Look in the NHibernate documentation for the "table per subclass" model of inheritance. It will actually implement this as a LEFT JOIN, so that when you load a Part, it creates an instance of either your Part or your ProducedPart class depending on whether the other row is present. You'll find documentation on nhibernate.info.
I'm not sure you could make ProducedPart read-only doing this though.
I'm assuming from this:
WHERE pp.ProductionYear = '2009'
that you want the subclass only where the production year is 2009, i.e. if when there is a record in t_PartProduction for a different year, you want this Part treated as a plain Part object, not a ProducedPart, then you could consider creating a view definition within your database that is a filtered version of t_PartProduction, then making your subclass join to this view rather than the base table.