nhibernate query with child entities and lazy="false" - linq

I have a problem with seperate sql queries being generated for every item in a child collection when selecting the Parent.
I have a Parent object with an IList collection of Child objects.
If I run the following code using linq to nhibernate:
IList parents = _repository.ToList();
I get the sql statements like the following:
SELECT * FROM Parent
SELECT * FROM Child WHERE ParentId = 1
SELECT * FROM Child WHERE ParentId = 2
SELECT * FROM Child WHERE ParentId = 3
SELECT * FROM Child WHERE ParentId = 4
etc etc
This is obviously extremely inefficient and assume it must be something to do with the mapping files?
Below is the mapping for the Child collection:
<bag name="Children" lazy="false" table="Child" cascade="all-delete-orphan">
<key column="ParentId"/>
<one-to-many class="Child" />
</bag>
Trust this is a newbie mistake somewhere.
Any help greatly appreciate.
S

It all depends on what _repository.ToList() is doing under the covers. You can force "eager" fetching of your collections via HQL syntax similar to the following:
"from Parent inner join fetch Children"
HQL statements are meant to be flexible, and so they tend to ignore your collection mapping and join strategies defined either fluently or in the hbm xml files.
You should now see only a single query executed against the database.

Look at this Linq for NHibernate and fetch mode of eager loading. You can manage your fetch strategy in the mapping file if your subcollection always needs to be in context. However, NH best practice recommends against this. Instead we always keep collections lazy, and set fetching strategies on the queries where appropriate.

Related

Ignite SQL tool query for collections within object

I am using Ignite v2.1 and dbeaver to query caches. Is it possible to query collections within a objects in the cache, or complex object within object in the cache? And if so, what it the syntax?
For example, if I have a cache such as IgniteCache and Person looked like the following, what would the syntax be to 1) select the address and 2) select the siblings names & addresses?
class Person {
String name;
Addresss address;
Collection<Person> siblings;
}
It is not possible to do SQL over nested collections in Ignite: SQL standard does not support such things. SQL tables are flat.
Think regular SQL databases: you need to introduce Person.id and Person.parentId (for one-to-many), or a separate mapping table (for many-to-many), then use SQL JOIN to query siblings.
You will have to declare QueryEntity for this cache, with list of fields and indexes on this cache, then you can use its fields in SQL queries. Annotations driven setup is explained in the same doc, pick one which suits you better.
Then the 1) will probably be something like SELECT ADDRESS FROM PERSONCACHE.PERSON WHERE NAME = ?.
Foreign keys are not supported, however, and I'm don't think that siblings setup will work. It doesn't work like that for relational databases unless you add join tables. Ignite is not a graph database.

LINQ to CRM - OR in Where clause

I am trying to bring some data from Dynamics CRM 2011 using LINQ. The goal is to bring all Contact records that have changes since certain date OR have a child entity (PERC files) changed since that same date. The query looks like that:
// Bring all students who have changes (at Contact entity) after specific date
// momentInTime or the status of any of their perc files has been changed since
// that date
var students = (from c in ContactSet
join pl in cga_portallogonSet on c.Id equals pl.cga_ContactId.Id
join ef in cga_percfileSet on c.Id equals ef.cga_StudentId.Id
where
(pl.cga_PortalLogonRole.Value == 284970000) // student
where
(c.ModifiedOn >= momentInTime || c.CreatedOn > momentInTime)
||
(ef.cga_statuschangedate >= momentInTime)
select c.cga_StudentNumber).Distinct().ToList();
This produces the following error message:
'Contact' entity doesn't contain attribute with Name = 'cga_statuschangedate'.
I cannot figure out how to do OR on two different entities. The MSDN says you need WHERE clause for each entity:
where Clause
In order to filter the result set, where clauses can be added against one or more of the >entities. Each where clause may only contain conditions against an individual entity type. >A composite condition involving multiple entities is not valid. Instead, each entity >should be filtered in separate where clauses.
http://msdn.microsoft.com/en-us/library/ff681565.aspx
Is there another way of achieving what I need?
Unfortunately you cannot achieve what you want in a single linq statement beacuse the liunq provider they use boils down to fetchXML, and fetchXML does not support the scenario you are using.
More detail... Fetch gives you condition's inside of entity's or link-entity's. These condition elements cannot have attributes in them from other linked entities, only the direct parent entity or link-entity. Here is one of many microsoft forum posts referencing this limitation of fetchXML
Probably not the answer you were looking for, eh? As an ugly alternative you you can run two separate queries and filter in memory (as damaging as that may be to performance). Or better yet if you are an on-premise deployment you can write some sql against the filtered views. Good luck.

Performace issue using Foreach in LINQ

I am using an IList<Employee> where i get the records more then 5000 by using linq which could be better? empdetailsList has 5000
Example :
foreach(Employee emp in empdetailsList)
{
Employee employee=new Employee();
employee=Details.GetFeeDetails(emp.Emplid);
}
The above example takes a lot of time in order to iterate each empdetails where i need to get corresponding fees list.
suggest me anybody what to do?
Linq to SQL/Linq to Entities use a deferred execution pattern. As soon as you call For Each or anything else that indirectly calls GetEnumerator, that's when your query gets translated into SQL and performed against the database.
The trick is to make sure your query is completely and correctly defined before that happens. Use Where(...), and the other Linq filters to reduce as much as possible the amount of data the query will retrieve. These filters are built into a single query before the database is called.
Linq to SQL/Linq to Entities also both use Lazy Loading. This is where if you have related entities (like Sales Order --> has many Sales Order Lines --> has 1 Product), the query will not return them unless it knows it needs to. If you did something like this:
Dim orders = entities.SalesOrders
For Each o in orders
For Each ol in o.SalesOrderLines
Console.WriteLine(ol.Product.Name)
Next
Next
You will get awful performance, because at the time of calling GetEnumerator (the start of the For Each), the query engine doesn't know you need the related entities, so "saves time" by ignoring them. If you observe the database activity, you'll then see hundreds/thousands of database roundtrips as each related entity is then retrieved 1 at a time.
To avoid this problem, if you know you'll need related entities, use the Include() method in Entity Framework. If you've got it right, when you profile the database activity you should only see a single query being made, and every item being retrieved by that query should be used for something by your application.
If the call to Details.GetFeeDetails(emp.Emplid); involves another round-trip of some sort, then that's the issue. I would suggest altering your query in this case to return fee details with the original IList<Employee> query.

NHibernate query mapped collection

In my ASP.NET web-application I use NHibernate to persist my "User"-Instances, where each of them has a "Entries" - collection. It is a typical one-to-many mapping and it works just fine. The mapping-code for the entries looks like this:
<bag name="Entries" cascade="all-delete-orphan">
<key column="UserID" />
<one-to-many class="MyApp.Entities.Entry, MyApp.Entities" />
</bag>
Now I have a page, where I want to display a grid with all the entries of the logged-in user. To do so, I could simply bind the "Entries" property of the current user to the Grids "DataSource" - property. This also works just fine, but this also means, that the grids built-in paging-functionality (Telerik RadGrid) doesn't have any effect on database-performance, because all the entries will be loaded each time when displaying the grid.
Therefore I could apply my custom-paging, where I only fetch the rows which I need to display the grids current page. A typical Linq2NHibernate query looks like this:
var query = from entry in Session.Linq<Entry>()
where entry.User == currentUser
select entry;
query.Skip(pageNum * pageSize).Take(pageSize).ToList();
Using this approach I need to extend my repository altough NHibernate has already done the mapping between User and Entry...
My question is: If I use LINQ to directly query the "Entries"-collection of my "User"-object - does this mean, that all the Entries will be loaded from the database and then filtered in memory or would this be translated to a real "database"-query, so that I could use this much more comfortable approach to implement paging?
Example:
myGrid.DataSource = currentUser.Entries.Skip(pageNum * pageSize).Take(pageSize).ToList();
J4I: Of course I use lazy-loading in the mapping files...
Thank you in advance!
LINQ on the collection will always be LINQ-to-objects, as they don't implement IQueryable, so you'd be loading everything in memory.
A query is the only possible approach at this moment.

nhibernate table pr hierarchy fetching specific class with LINQ

I have a class hierarchy mapped into one table. There is one superclass and 8 different sub classes. A lot of my queries needs to fetch e.g. 2 of the sub classes only for a specific date.
The table has a discriminator column that nhibernate itself uses. But when using LINQ for querying it is not possible to use this discriminator as there is no property for it.
Is there a commonly used trick for only fetching specific sub class when using nhibernate ?
For now I first have Linq 4 Nhiberneate query that fetches all sub classes into a given period. And then uses Linq 4 objects to filter on the sub classes that I need.
Is it possible to expose the discriminator column of the table as a property and thereby be able to make a where clause on it ?
In Hql querying subclasses is done by class, so you'd do
from subclass
where subclass.DateTime = :myDateTime
The docs also say you can query hierarchies by the special class property, eg:
from Eg.Cat cat where cat.class = Eg.DomesticCat
I don't know if this is possible with the Criteria API or NH Linq Provider.
You could always get all the instances with the correct time, and then filter client side, eg:
var allCandidates = from super in session.Linq<SuperClass>()
where super.Date > DateTime.Now.AddDays(-1)
select super
var results = from candidate in allCandidates
where candidate.GetType() == typeof(SubClass)
select candidate
It's a bit nasty, and if the subset of classes you're querying is always the same, you might be better off inserting another class in the hierarchy and querying that.

Resources