Fetching with JoinQueryOver: Get greatgrandchildren, know father - nhibernate

Object Structure:
A house has many rooms.
A room has many tables.
A table has many vases (on it).
House > Rooms > Tables > Vases.
I'd like to use JoinQueryOver to select all tables with vases that are red - in a particular house.
I thought to do this:
var v = session.QueryOver<House>()
.Where(x => x.ID == HouseID)
.JoinQueryOver<Room>(x => x.Rooms)
.JoinQueryOver<Table>(x => x.Tables)
.JoinQueryOver<Vase>(x => x.Vases)
.Where(x => x.Color == "Red")
.SingleOrDefault<House>();
This was an approach I tried (of the many that failed). I don't really want the House and Room info.
Ultimately, I'm looking for a List of Tables (in a particular house), with their collections of Vases (that are red) fetched.
Thanks for the help!
Edit
Something like this would be nice:
var v = session.QueryOver<Table>()
.Where(x => x.Room.House.ID == HouseID) // this Where won't work.
.JoinQueryOver<Vase>(x => x.Vases)
.Where(x => x.Color == "Red")
.List().ToList();

var v = session.QueryOver<Table>()
.JoinAlias(x => x.Room, () => room)
.Where(() => room.House.ID == HouseID)
.JoinQueryOver<Vase>(x => x.Vases)
.Where(x => x.Color == "Red")
.List();

Related

How to convert my partial In Memory LINQ GroupBy query to complete Database Query or should I use raw sql?

I tried different ways to solve this but either it wont let me include or it gives error for the GroupBy statement.
In the above code, I am trying to Group the MedicineEquipments by FOREIGN KEY i.e LocationId, and take the latest record with that LocationId and also include Location and MedicineEquipmentNavigation along with the record.
var medicineEquipmentShops = await dbContext.MedicineEquipments
.Where(x => x.CityId == cityId && x.MedicineEquipmentId == medicineEquippmentId)
.Include(x => x.Location)
.Include(x =>x.MedicineEquipmentNavigation)
.ToListAsync();
medicineEquipmentShops = medicineEquipmentShops.GroupBy(x => x.LocationId)
.Select(x => x.OrderByDescending(y => y.UpdatedOn).FirstOrDefault())
.OrderByDescending(x => x.IsVerified)
.ThenByDescending(x => x.Stock)
.ThenByDescending(x => x.Votes)
.ToList();

Can't build 2 tables JOIN with only certain fields to select in Nhb 4

I try to run query like this with Nhibernate v.4:
Select o.Number, c.Address
From Order o join Client c on o.ClientId = c.Id
Where c.Name = "John"
Tried many ways to do that with JoinQueryOver and JoinAlias but nothing helps, endup with error "could not resolve property: Address of Order"
Session.QueryOver<Order>()
.JoinQueryOver(s => s.Client)
.Where(() => c.Name == "John")
.SelectList(x => .Select(Projections.Property<Order>(o => o.Number)
.SelectList(x => .Select(Projections.Property<Order>(o => o.Client.Address))
or like this
...
.SelectList(x => .Select(Projections.Property<Order>(o => o.Number)
.SelectList(x => .Select(Projections.Property<Client>(c => c.Address))
What is the right way to build the query or something very similar? Problem with 'Select' operator, 'Where' part works fine. I can also build non-join queries by this 2 entities separate from each other and it works well, but no idea how to join them
Finally I've figured out how to make it work:
Client client = null;
OrderClientDto dto = null;
var result = Session.QueryOver<Order>()
.JoinAlias(o => o.Client, () => client)
.Where(() => c.Name == "John")
.SelectList(x => x
.Select(o => o.Number).WithAlias(() => dto.Number)
.Select(() => o.Client.Address).WithAlias(() => dto.Address))
.TransformUsing(Transformers.AliasToBean<OrderClientDto>())
.List<OrderClientDto>();
Nhb is far from being intuitive and convenient. Same query is much easier to write in EF.

NHibernate QueryOver Where with internal select

I have a problem with translating this SQL into QueryOver notation. Can you help me?
SELECT * FROM Alerts a
WHERE a.CreatedOn = (
SELECT MAX(b.CreatedOn) FROM Alerts b WHERE b.UserFk=a.UserFk);
I try to select last alert for every user. I use CreatedOn and cannot use Id.
I have so far:
session.QueryOver(() => alertAlias)
.SelectList(list => list
.Select(() => alertAlias.User.Id)
.SelectSubQuery(
QueryOver.Of<Alerts>()
.Where(x => x.User.Id == alertAlias.User.Id)
.OrderBy(x => x.CreatedOn).Desc
.Select(x => x.CreatedOn)
.Take(1)));
I know it adds user's last alert date to every user's alert row. But I want to have only last alerts.
Your attempt is using subquery inside of a SELECT statement. But we need to move it into WHERE. This should be the way:
// this is a subquery (SELECT ....
var subquery = QueryOver.Of<Alerts>()
.Where(x => x.User.Id == alertAlias.User.Id)
.OrderBy(x => x.CreatedOn).Desc
.Select(x => x.CreatedOn)
.Take(1)));
// main Query could now have or do not have that subquery selected
var query = session.QueryOver(() => alertAlias)
.SelectList(list => list
.Select(() => alertAlias.User.Id)
// could be there
.SelectSubQuery(subquery)
)
// but mostly here we do use WHERE clause
.WithSubquery
.WhereProperty(() => alertAlias.CreatedOn)
.Eq(subquery)
;
// such a query could be returned as a list of arrays
var results = query.List<object[]>();
We can also use some Result Transformer, but this is another story...

NHibernate QueryOver with JoinQueryOver select all columns

I have some QueryOver with several joins and the result I get is OK in terms of the returned objects. This is the code>
var l = session.QueryOver<Discount>(() => discount)
.JoinQueryOver<ConPrdGrp>(r => r.ConPrdGrps)
.JoinQueryOver<PrdGroupTree>(k => k.PrdGroupTree)
.JoinQueryOver<Product>(g => g.Products)
.Where(p => p.ProductID == Product.ProductID)
.And(() => discount.FomDato <= DateTime.Now && discount.TomDato >= DateTime.Now).List();
But if I look at the SQL statement, I can see that the generated query selects ALL columns from all joined tables although the result only returns a list of Discount objects. I can get some properties of Discount using projections and the query will be much smaller. But how I can instruct NHibernate to get just columns from the Discount table and not from all joined tables?
As far as I know there is NOT a simple way like: .Select(Projections.Properties<Discount>()). Check this a bit outdated question (NHIbernate: Shortcut for projecting all properties?)
What you can do is explicitly name the columns you would like to see:
... // the QueryOver you have
.SelectList (l => l
.Select(() => discount.ID).WithAlias(() => discount.ID)
.Select(() => discount.Code).WithAlias(() => discount.Code)
...
)
.TransformUsing(Transformers.AliasToBean<Discount>())
...
The second approach could be to create the Subquery, and then just QueryOver<Discount>() 16.8. Subqueries
QueryOver<Discount> subQuery =
QueryOver.Of<Discount>(() => innerDiscount)
.JoinQueryOver<ConPrdGrp>(r => r.ConPrdGrps)
.JoinQueryOver<PrdGroupTree>(k => k.PrdGroupTree)
.JoinQueryOver<Product>(g => g.Products)
.Where(p => p.ProductID == Product.ProductID)
.And(() => innerDiscount.FomDato <= DateTime.Now
&& innerDiscount.TomDato >= DateTime.Now).List()
.Select( Projections.Property(() => innerDiscount.ID))
;
var query = session.QueryOver<Discount>(() => discount)
.Where(Subqueries.PropertyIn("ID", subQuery.DetachedCriteria))
;

Fluent Nhibernate QueryOver and Joins

I'm in the process of learning Fluent nHibernate. I'm having trouble with building a query thats not quite the same as the classic examples I've found online. Typically I've found this example:
IQueryOver<Cat,Cat> catQuery =
session.QueryOver<Cat>(() => catAlias)
.JoinAlias(() => catAlias.Kittens, () => kittenAlias)
.Where(() => catAlias.Age > 5)
.And(() => kittenAlias.Name == "Tiddles");
So from what I understand in this example a Cat object is being returned after being joined on Kittens and then filtered using the kittens name and the cat's age. And the join works because the Cat object has a property called Kittens.
An example of what I'm trying to do would look like this:
Forest f = null;
Tree t = null;
ForestsFound = session.QueryOver<Forest>(() => f)
.JoinAlias(() => t.Forest, () => f)
.Where(() => t.NumberOfTrees > 1000)
.List<Forest>()
.ToList<Forest>();
A forest is essentially a lookup table, it's the Tree that has a link to what forest the tree is in but I want to return a distinct list of forests. So in regular sql it would look like:
select f.*
from Forest f
inner join Tree t
on t.Forest_id = f.ID
where t.NumberOfTrees > 1000
If you have a relationship from Forest -> Trees then you can do this:
Forest f = null;
Tree t = null;
ForestsFound = session.QueryOver<Forest>(() => f)
.JoinAlias(() => f.Trees, () => t)
.Where(() => t.NumberOfTrees > 1000)
.List<Forest>();