NHibernate Query parent and child objects eagerly without join - nhibernate

I have simple domain with Order and OrderLines. Is it possible to load the Order and associated OrderLine objects without a join? I'm trying to use the Future/FutureValue to perform two simple queries. I'm hoping that NHibernate knows how to combine these in the cache. I'm using NHibernate 3.2 with code only mapping.
So far here is what I have:
// Get all the order lines for the order
var lineQuery = session.QueryOver<OrderLine>()
.Where(x => x.WebOrder.Id == id).Future<OrderLine>();
// Get the order
var orderQuery = session.QueryOver<WebOrder>()
.Where(x => x.Id == id)
.FutureValue<WebOrder>();
var order = orderQuery.Value;
This works as expected sending two queries into the database. However when I use loop to go through order.OrderLines NHibernate send another query to get the order lines. My guess is that because I'm using constraints (Where(x => ...) NHibernate doesn't know how to get the objects from the session cache.
Why do I want to do this without join
I know I can use Fetch(x => x.OrderLines).Eager but sometimes the actual parent (in this case Order) is so large that I don't want to perform the join. After all the result set contains all the order columns for each orderline if I perform the join. I don't have any raw numbers or anything I'm just wondering if this is possible.

it's quite possilbe. see nHib's fetching strategies.
you can choose either 'select' (if you're only dealing with one Order at a time) or 'subselect'.

Related

Loop or DB query, Which one causes more time?

I have a table which has 8 column, but for a certain functionality I need only 4 column values out of the table. So I am currently selecting only the 4 column and mapping it to my entity and returning it. When I am mapping I believe there is a loop running on the retrieved value. So what is the best practice ? should I just retrieve all 8 values from DB or get only what I need and map it to entity and return it?
var users= (from u in context.Users
join r in base.DatabaseContext.Users
where s.userId== id
select new {
Id=u.Id,
FirstName=u.FirstName,
LastName =u.LastName,
IsActive=u.IsActive,
}).GroupBy(x => x.Id).Select(y => y.FirstOrDefault()).AsEnumerable()
.Select(x => new WebCore.Model.User // Here i believe there will be an iteration on the retrieved result
{
Id = x.Id,
FirstName = x.FirstName,
LastName = x.LastName,
IsActive = x.IsActive,
}).AsQueryable();
return users;
My understanding is that IO operation causes the main performance issue. but at this scenario I am a bit confused. If possible please provide an detail explanation for me to understand the issue clearly.
As a rule of thumb, you should only query the fields you need in your application. Querying more fields than needed will result in an overhead reading these fields from these database and transporting the data over the network. So in your case you should just query 4 columns, because that is what you need for now.
Regarding your concerns about your LINQ query, these queries are generally relatively efficient and I strongly advise against premature optimisation until it turns out to be a bottleneck. See Donald Knuth's opinion about this topic in my comment.

Translate this Sql query into NHibernate Linq or Criteria?

I have a security schema where certain entities are secured by having a SecureEntity reference. A SecureEntity has a collection of RolePermissions, each of which has an Allow flag and a Priority. The idea is to match the user's roles against the RolePermissions on the SecureEntity. For example, a user may be allowed by their lowest priority permission but denied by a higher one, so it is the highest one that we are interested in. In this example the root entity I am querying is called ProcessCategory.
(SecureRoleId is the match for the user's role; SecureRoleName is just a string description.)
Assume a user has roles (1,2) and the SecureEntity has RolePermissions:
SecureRoleId = 1, Priority = 0, Allow = true
SecureRoleId = 2, Priority = 1, Allow = false
In this case the entity would not be selected. But if the user only had role 1, the entity would be selected. Of course, the SecureEntity may contain a bunch of other roles that the user does not have and are irrelevant.
The sql code below works and does this: 'select the entity if the highest priority role permission that the user also has is Allow=true'. So it basically filters RolePermission on the users own roles (IN clause), sorts by Priority, and takes the highest one if that is an Allow.
Here is the Sql:
select pc.* from ProcessCategory pc
join SecureEntity se
join RolePermission rp on se.SecureEntityId = rp.SecureEntityId
on pc.SecureEntityId = se.SecureEntityId
where rp.RolePermissionId = (select top 1 RolePermissionId
from RolePermission
where Allow = 1
and SecureEntityId = se.SecureEntityId
and SecureRoleId in(0,1)
order by Priority desc)
There may be another way to write the above Sql but it does what I need. Ideally I would like to achieve this using NHibernate Linq or Criteria. I spent a few hours trying to get Linq to work and failed with various 'invalid operation' exceptions on the inner join to RolePermission. I don't have much experience with ICriteria or MultiCriteria and would be interested if anybody can help me.
Note that the Fluent mapping for the objects is straightforward:
<some-entity>.References(x => x.SecureEntity)
and
SecureEntity.HasMany(x => x.RolePermissions).Not.Inverse();
Okay. I couldn't get this to work using native NH Linq, although that doesn't mean that it is not possible. But I looked through all the NH unit tests for Linq and couldn't find anything equivalent.
To get it working I created a database function called UserHasPermission that does everything in:
on pc.SecureEntityId = se.SecureEntityId
where rp.RolePermissionId = (select top 1 RolePermissionId
from RolePermission
where Allow = 1
and SecureEntityId = se.SecureEntityId
and SecureRoleId in(0,1)
order by Priority desc)
This works with any kind of secured entity. I then mapped that function as an NH Linq function by following the instructions in this page: http://wordpress.primordialcode.com/index.php/2010/10/01/nhibernate-customize-linq-provider-user-defined-sql-functions/.
If you follow those instructions, you have to create a normal LinqToObjects extension in C# that has an identical signature to your database one. You can then do your NH Linq query like:
return base.Query<T>().Where(c => ((ISecureEntity)c)
.SecureEntity.Id
.UserHasPermissions(user.SecureRoleIdsCsv) == 1);
The only problem I found was that my original Sql function returned a bit, which I mapped to a NH Boolean type. However this produced a really strange bit of sql that had several "Where ''True'' = ''True''" clauses that blew up in Sql Server. So I changed the result to an integer and everything worked okay. A bit counter-intuitive, but...
Doing it this way allowed me to carry on transparently using Linq for all my queries, without affecting existing code, because it automatically prepended each query with the security check.
Note that I looked in the Rhino Security source code and it uses a multiple criteria that is much too complex for me to understand with my limited NH knowledge. If I had done it using CreateCriteria, could I have combined it with Linq though?
The instructions in the above link do not make it clear that when you have created your own Dialect that registers your Sql function, you have to make sure you reference it in your NH configuration file (or code), otherwise you will get some kind of 'unknown type' exception.

Efficently returning parent and child records with NHiberate

I am trying to efficiently work with parent & child (post & tags) entities. A sample of the code can be seen here: http://gist.github.com/297464
Using the following results in less than 10 distinct Post entities if any of Post contains more than 1 tag.
var posts = session
.CreateCriteria<Post>()
.SetMaxResults(10)
.SetFetchMode("Tags", FetchMode.Eager)
.List<Post>();
If I remove the .SetFetchMode line above, I get the 10 records I am looking for, but all of the Tag entities are queried and then filtered in memory.
It seems like I should be able to instruct NHiberate to either pass in a list of PostIds or do a join.
I am pretty new to NHiberate so it is also entirely possible I am going at this completely wrong.
Thanks,
Scott
The problem is that SetMaxResults is not applied to the number of root entities returned from the query, it is translated into a T-SQL TOP (in the case of SqlServer), which is applied to the result from a join query. Since there is one row in the result set for each child of a root entity the TOP will not have the desired effect.
To achieve a limit on the number of root entities you could use a join query with a subquery that contains the SetMaxResults limit.
// Select the ids of the first ten posts
var subquery = DetachedCriteria.For<Post>()
.SetMaxResults(10)
.SetProjection(Projections.Property("Id"));
// Do a join query with posts and tags, for the posts who's ids are
// in the result of the subquery
var posts = session.CreateCriteria<Post>()
.SetFetchMode("Tags", FetchMode.Join)
.Add(Subqueries.PropertyIn("Id", subquery))
.SetResultTransformer(Transformers.DistinctRootEntity)
.List<Post>();

nhibernate: how to map aggregates

Good afternoon, I'm trying to learn nHibernate and it's not terribly clear.
I need to get the result of an sql query:
select patient.name,
discipline.description,
sum(patient.enddate - patient.startdate) as totaltime
from treatment
join patient on patient.id = treatment.patientId
join discipline.id = treatment.disciplineId
I don't need to persist the result, just display it.
If I use hql directly:
What objects will it instantiate and return to me? Will it dynamically build a list of objects containing fields identical to the columns in the result set? The docs leave out this information.
If I need to make a mapping:
Do you create a mapping to a 'meta' object or to one of the joined tables (say 'treatment')?
Thanks
This can be achieved by using DTO objects ("data transfer objects"). You create an object that contains only the data you wish to return. Add an initializing constructor. Then your hql can be of the form:
select new mydto( x.value, y.value ) from x join x.y;
It doesn't seem to like using aggregate functions in the object constructor though.

(N)Hibernate Auto-Join

I'm developing a web- application using NHibernate. Can you tell me how to write a NHibernate Query for the following SQL query:
SELECT v1.Id
FROM VIEW v1
LEFT JOIN VIEW v2 ON v1.SourceView = v2.Id
ORDER BY v1.Position
It's basically a auto-join but I don't know how to write this in Nhibernate. Lets say the property names are the same as the table column names.
You could just perform the select on the original entity and make the association between the two objects "lazy = false". As long as the entities are mapped then both will be returned and you wont get a lazyloadingexception when trying to access the object.
If you don't want to map "lazy=false" then you can also iterate through the results and perform some sort of operation (such as asking if it is null; if(v1.AssocatedObject == null){}) to ensure the data is loaded while the session is open.
Update:
I think there is actually a better one than that in, NHibernateUtil.Initialise() that can initialise a collection without having to wander through it.