NHibernate Projection using SqlQuery - nhibernate

I'm trying to reproduce the HqlQuery style 'select new ObjectToProjectOut' functionality. i.e. take a list of columns returned from a query and return as a list of ObjectToProjectOut types that are instantiated using a Constructor with as many parameters as the columns in the query.
This is in effect what 'select new ObjectToProjectOut' achieves in Hql.... but clearly that's not available in SqlQuery. I think I need to set a result transform and use either PassThroughResultTransformer, DistinctRootEntityResultTransformer etc to get it to work.
Anyone know what I should use ?

ok.... after looking at the NHibernate code it seems that I was looking for AliasToBeanConstructorResultTransformer.... of course!
However I may have found an nHibernate bug. If you have the same column name returned twice from two different tables (market.name and account.name, say) then by the time nHibernate returns the array from the db to the transformer, the first occurance of 'Name' will be used for both. Nasty.
Work around is to uniquely alias. With Hql, the sql generated is heavily aliased, so this is only a bug with SqlQuery.
Grrrr. Today must be my day, also found another nHibernate bug/issue I've posted to StackOverflow for comment.

You could use the AddEntity method to fill entities from a SQL query.
Here are two examples from the NHibernate docs:
sess.CreateSQLQuery("SELECT * FROM CATS")
.AddEntity(typeof(Cat));
sess.CreateSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS")
.AddEntity(typeof(Cat));

Related

Keyword based JPA query with statuses as Enums and with NOT clause [Kotlin]

I have a Keyword based JPA query I need to modify in order to exclude records with a particular status. Currently, I have the following:
findAllByLatestVersion_Entity_DataFieldGreaterThanEqualAndLatestVersion_AnotherFieldNull(datefield: Istant, pageable: Pageable)
I do not want to parameterise, therefore I would like to have the query to work as there was a WHERE clause stating that the status IS NOT C, for example. I am struggling to find clear documentation on how to go about. Is it possible to write something along these lines:
findAllByLatestVersion_Entity_DataFieldGreaterThanEqualAndLatestVersion_AnotherFieldNullAndLatestVersion_StatusCNot(datefield: Istant, pageable: Pageable)
Thank you
No this is not possible with query derivation, i.e. the feature you are using here. And even if it were possible you shouldn't do it.
Query derivation is intended for simple queries where the name of the repository method that you would choose anyway perfectly expresses everything one needs to know about the query to generate it.
It is not intended as a replacement for JPQL or SQL.
It should never be used when the resulting method name isn't a good method name.
So just formulate the query as a JPQL query and use a #Query annotation to specify it.

NHibernate restriction Count of child collection

Take for example: a Person that has a collection of Pets. I want to only list the Persons that have at least 5 pets.
I have tried:
var result = (from a in UnitOfWork.CurrentSession.QueryOver<Person>()
where a.Pets.Count >4
select a
).List()
But it says it does not recognize the property Count (which makes sense because it is not a DB field). I also tried Count() and it still doesn't work saying it doesn't understand that function (throws exception).
I've tried all kinds of subqueries and criteria methods but I don't know enough to put it all together. And I don't know whether I shold use LINQ or HQL or QueryOver or Criteria...It would be much much mch easier in SQL but I don't want to "cheat"
I have been searching google like crazy, and everything I found either does not compile or I get a runtime error
You are using QueryOver instead of LINQ (Query<T>() extension method)

Hibernate Throws a SQLException When Distinctly Selecting only Two of Three Mapped Columns

I have a table, CityComplete, with columns "USPSCITY", "STATE" and "ZIPCODE"
I have an existing SQLQuery that distinctly selects USPSCITY and STATE based on a fuzzy search. However, when I call list() I get an exception:
19. ResultSet.getString(ZIPCODE)
java.sql.SQLException: Column 'ZIPCODE' not found.
The SQLQuery's entity is set to the CityComplete object.
Is there any way to have Hibernate not try and get ZIPCODE, or have it be part of the result set in some way?
What's the best way to resolve this, other than using Criteria, setting a virtual column with null data, or just getting a full result set and handling distinction on the code side?
When you perform a regular Hibernate query (HQL or Criteria), Hibernate will try to map the resultset based on the properties of the entities which you specified in the mapping. If you are not bringing the "promised" data from the database, you'll need to handle the mapping by yourself, using a ResultTransformer. In this case, you'd still use your CityComplete, but they will be without a ZIPCODE. Unfortunately, there's not much documentation about how to use a ResultTransformer, but you can take a look at the Hibernate's JavaDoc and see if there's one that you could use. If not, you'd need to implement your own:
http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/transform/ResultTransformer.html

nhibernate linq: projection to DTO and columns

I've recently upgraded my Linq provider to the new AST one. (NH3 on NuGet)
With the previous provider I was using linq to do "inline projections
to my DTO"
e.g.
from o in Session.Query<MyObject>()
select new MyObjectDTO {
Name = o.Name,
SubName = o.OtherObject.Name,
Sub2NAme = o.OtherObject2.Name
}
and this would generate a
SELECT o.Name, sn1.Name, sn2.Name FROM .....
JOIN.... JOIN....
statement.
Once I upgraded my provider I found a lot of select statements being
fired off. (My projected object is more complex than above).
I have come accross Fetch/FetchMany, which might help with the number
of queries, but as far as I can tell it means the full object will
come back for each flattened field I require.
Is there a way I can get the smallest possible number of columns required for the projection to be selected, rather than loading the full object graph to the project with?
Thanks,
Chris
It must be something with your usage of the result (like iterating many times the IQueryable), something odd with the mappings, or some complexity that was removed from the example.
I just tried that exact query, and only one SQL statement was generated.

nhibernate and DDD suggestion

I am fairly new to nHibernate and DDD, so please bear with me.
I have a requirement to create a new report from my SQL table. The report is read-only and will be bound to a GridView control in an ASP.NET application.
The report contains the following fields Style, Color, Size, LAQty, MTLQty, Status.
I have the entities for Style, Color and Size, which I use in other asp.net pages. I use them via repositories. I am not sure If should use the same entities for my report or not. If I use them, where I am supposed to map the Qty and Status fields?
If I should not use the same entities, should I create a new class for the report?
As said I am new to this and just trying to learn and code properly.
Thank you
For reports its usually easier to use plain values or special DTO's. Of course you can query for the entity that references all the information, but to put it into the list (eg. using databinding) it's handier to have a single class that contains all the values plain.
To get more specific solutions as the few bellow you need to tell us a little about your domain model. How does the class model look like?
generally, you have at least three options to get "plain" values form the database using NHibernate.
Write HQL that returns an array of values
For instance:
select e1.Style, e1.Color, e1.Size, e2.LAQty, e2.MTLQty
from entity1 inner join entity2
where (some condition)
the result will be a list of object[]. Every item in the list is a row, every item in the object[] is a column. This is quite like sql, but on a higher level (you describe the query on entity level) and is database independent.
Or you create a DTO (data transfer object) only to hold one row of the result:
select new ReportDto(e1.Style, e1.Color, e1.Size, e2.LAQty, e2.MTLQty)
from entity1 inner join entity2
where (some condition)
ReportDto need to implement a constructor that has all this arguments. The result is a list of ReportDto.
Or you use CriteriaAPI (recommended)
session.CreateCriteria(typeof(Entity1), "e1")
.CreateCriteria(typeof(Entity2), "e2")
.Add( /* some condition */ )
.Add(Projections.Property("e1.Style", "Style"))
.Add(Projections.Property("e1.Color", "Color"))
.Add(Projections.Property("e1.Size", "Size"))
.Add(Projections.Property("e2.LAQty", "LAQty"))
.Add(Projections.Property("e2.MTLQty", "MTLQty"))
.SetResultTransformer(AliasToBean(typeof(ReportDto)))
.List<ReportDto>();
The ReportDto needs to have a proeprty with the name of each alias "Style", "Color" etc. The output is a list of ReportDto.
I'm not schooled in DDD exactly, but I've always modeled my nouns as types and I'm surprised the report itself is an entity. DDD or not, I wouldn't do that, rather I'd have my reports reflect the results of a query, in which quantity is presumably count(*) or sum(lineItem.quantity) and status is also calculated (perhaps, in the page).
You haven't described your domain, but there is a clue on those column headings that you may be doing a pivot over the data to create LAQty, MTLQty which you'll find hard to do in nHibernate as its designed for OLTP and does not even do UNION last I checked. That said, there is nothing wrong with abusing HQL (Hibernate Query Language) for doing lightweight reporting, as long as you understand you are abusing it.
I see Stefan has done a grand job of describing the syntax for that, so I'll stop there :-)