NHibernate : Count childrens' children - nhibernate

I have an entity type A. Which has many B's. The B entity has many C's.
I need to count how many C's does an A entity have. How can this be done using NHibernate Criteria API?
Using LINQ to NHibernate I was unable to get results since it throws an exception (see this question)

This query becomes simpler if you use C as starting point of the query, rather than A. This is possible since you use bidirectional mappings, according to the mapping you show in your other question.
The way I would do this is to find all Cs which have a B which has a given A, and then count the found Cs.
To Add a constraint on the B of a C, you can add an alias and then add restrictions to that alias. To perform a count query rather than returning the found Cs you can use the SetProjection method and specify a Count projection. Since the count projection returns a single integer value, use UniqueResult to get the count.
using (ISession session = SessionFactorySingleton.OpenSession())
{
int numberOfCsForA1 = session.CreateCriteria<C>()
.SetProjection(Projections.Count("Id"))
.CreateAlias("B", "b")
.Add(Restrictions.Eq("b.A.Id", a1.Id))
.UniqueResult<int>();
// ...
}
The SQL generated by this query looks like this:
SELECT count(this_.Id) as y0_
FROM [C] this_
inner join [B] b1_
on this_.IdB=b1_.Id
WHERE b1_.IdA = #p0;#p0 = 12
As you can see, it is a two-way join, since NHibernate is smart enough to realize that it does not need to join with the A table to get the id of a Bs A. Instead it simply looks at the IdA value of the B.

Related

LINQ SUM Nullable

I have a simple linq query
(From a In db.payments Group Join b In db.interestcharges On a.pid Equals b.pid Into totalinterest = Group, TotalInterestReceived = Sum(b.interest)) select a, TotalInterestReceived).toList()
b.interest is type decimal in DB.
Throws
"The cast to value type 'System.Decimal' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type."
This is because InterestCharges table may not have any interest records for pid.
I have tried sum(if(b.interest=nothing,0,b.interest) but this is translated by LINQ to if(b.interest=0, 0, b.interest) hence it never checks for null. Nothing else seems to work instead of nothing. I have tried vbNull, isDBNull(), no success. query works fine when the sum is not null. defaultifempty(0) may work but not sure how to use it in this scenario. Any pointers?
The GROUP JOIN statement indicates that you're attempting a LEFT OUTER JOIN. This is why you're receiving a NULL issue. By using JOIN for an INNER JOIN, then you won't stumble on this, but it also means that you will only see those items that have values for interest.
(FROM a in db.Payments
Join b in db.InterestCharges ON a.pid Equals b.Pid
SELECT a, TotalInterestReceived = SUM(b.Interest)
).toList()
It is possible to generate a sub-select which may get the values you're hoping for. The purpose here is that you get all payments, and then basically add in the Interest charges (or 0 if there are none).
(From a In db.Payments
Select a
, TotalInterestRecieved = (From b in db.InterestCharges
Where b.pid = a.pid
select b.Interest).DefaultIfEmpty(0).Sum()
).ToList
EDIT:
Another option would be to bypass EF entirely. Build a view in the database and query that view directly rather than attempting to access the underlying data via LINQ.
Most other suggestions I would have would involve iterating through the initial list of "Payments" and populating the values as needed. Which is fine for a small number of "Payments" but that is a O(n) solution.

SQL "not in" syntax and nested SELECT in Entity Framework

I recently used Entity Framework. For elementary CRUD operations, I have no problems, but for more complicated queries, I do not know how to do these.
For example: how to write a nested select? How to use the NOT IN operator?
The query that I want to write is:
SELECT *
FROM course
WHERE idCourse NOT IN (SELECT idCourse
FROM reservation
WHERE idStudent = 'value');
I do not know where to start. Could you please give me some advice?
If I do not misunderstood your question, you want to know how to write the question's query as LINQ-to-Entity query.
Examples could be:
var courses = context.Courses
.Where(c => c.Reservations.All(r => r.idStudent != "value"))
.Select(c => c);
// with eager loading
var courses = (from c in context.Courses.Include(c => c.Reservations)
where c.Reservations.All(r => r.idStudent != "value")
select c).ToArray();
var courses = (from c in context.Courses
join r in context.Reservations on c.idCourse equals r.idCourse
where r => r.idStudent != "value"
select c).ToArray();
The Contains() is equivalent to EXIST IN in a query. Well, 1st and 2nd nearly the same. Only difference is the Include method to show how you could eager load data.
In the 3rd query I use the join key word to do a join operation - equivalent to an INNER JOIN. The result will contain only records where a relation between a course and a reservation exists and the searched student ID is referenced in the reservation.
If you should not use LINQ for your querys, you should take a look. It's a perfect way to decouple your data access layer from persistence layer and you could test all your queries in code too.
Here you could get a very good entry into the subject.
EDIT:
Modified example code to fit NOT IN.
If you are having trouble executing complex queries with LINQ, you can also execute raw SQL queries. They are easy and faster than linq queries.
Here is an example in c#
var list = dc.Database.SqlQuery<YourCourceClass>(#"SELECT *
FROM course
WHERE idCourse NOT IN(SELECT idCourse
FROM reservation
WHERE idStudent = 'value');").ToList();

How to select one table using NHibernate CreateCriteria

How can I create the following SQL statement in Nhibernate using CreateCriteria:
SELECT distinct top 20 a.* from ActivityLog a
left join WallPost w on a.ActivityLogId = w.ActivityLogId left join ItemStatus i on i.StatusId = w.ItemStatus
I always tend to get all columns from all tables returned in the sql statement producing duplicates even though I map it to the ActivityLog table. I am also doing paging as the code below shows:
ICriteria crit = nhelper.NHibernateSession.CreateCriteria(typeof(Model.ActivityLog), "a").CreateAlias("a.WallPosts", "w",CriteriaSpecification.LeftJoin)
.CreateAlias("w.ItemStatus", "i", CriteriaSpecification.LeftJoin)
.SetMaxResults(pageSize).SetFirstResult(startRow).AddOrder(Order.Desc("a.Date"));
Thanks
H
Sounds like you have set lazy loading to false in your mapping files meaning that all the associations and child collections are being loaded up too. Can you verify that?
You ask "How to select one table using NHibernate CreateQuery" (HQL). In that case you can choose what to fetch using select.
In your text you're using criteria. AFAIK, you cannot directly control what columns you want to read. However, if you create a DetachedCriteria for the join, this won't be fetched.

writing SQL queries to get neighbour rows

I have come across some problems writing queries for getting neighbour rows and have no idea what to do about it.
This is the scenario (it is not purely implemented using SQL at the moment, but rather a mix of SQL and Java implementation) :
There is an entity A which has 1000 entity B, each entity B has 1000 entity C, each entity C has 1000 entity D. We need to use the information stored in D. At first we have a query to get all entity Ds inside entity A. Then we implement some logic so that we can navigate from a particular D to the next D or previous D, but this logic is not written as SQL queries.
Question 1
If I want to implement the navigation logic as SQL queries, how can I go to the next D in my select query? Suppose the original query is as simple as
select * from D
inner join C where C.ID = D.FK
inner join B where B.ID = C.FK
I am looking for a universal solution for both Oracle and SQL Server.
Question 2
How do I know what position is the current row (within the result of the above query). For example, if I want to implement some logic like "This is No. X of Y".
For those who are confused about what neighbor rows is, I mean the previous or next row of each row we get from the above query. The result query might be quite different with the one above, but you get the idea, I can specify the position of a particular D in the whole entity A using JAVA but I don't know how to do that using SQL.
If you are using Oracle, look into the LEAD and LAG keywords, they allow you to select with information from the rows before or after.

NHibernate HQL subselect left join?

I have the following issue and I would really appreciate your help:
I have all my filtering done through the HQL and one of the filters is a left outer join which must be a sub-select. So my thinking here is that I can create a dummy business object which I would like to populate (with an SP if possible) with data and use it in my left join.
Now how can I do that and still have all of the logic in 1 HQL query?
I guess the biggest issue for me is understanding how can I have this BO (not actually mapped to a table etc.) be used in a query where all the other BOs are mapped to tables etc.
I am trying to avoid doing any filtering in the actual C# code.
Thanks!
Example:
Entity A - mapped to table A
Entity B - mapped to table B
Entity C - mapped to table C
Entity D - not mapped to table - coming from SQL query or SP
HQL:
from A pbo
inner join B.EntityType etype
inner join C.EntityAddressList eadr
left join D.Level lvl
You cannot join to arbitrary SQL in HQL. So I don't think what you're trying to do is possible. You'll likely either have to map whatever D is, or write your query in SQL using Session.CreateSQLQuery(). You can still specify any entities that come back. See this article for reference. http://www.nhforge.org/doc/nh/en/index.html#d0e10274