HQL Fetch Join without knowing object implementation - sql

I'm having performance issues and I'm trying to add some fetch join to get some data in only one request.
My problem is :
I got a mapped object AbstractObject.
And I also got other mapped object like ObjectA, ObjectB etc... all are extending AbstractObject.
In my ObjectA I got a list of foos.
In my ObjectB I got a list of otherFoos.
What I'm trying to do :
I want to write a request like this :
entityManager.createQuery("SELECT ao FROM AbstractObject ao LEFT JOIN FETCH ao.foos LEFT JOIN FETCH ao.otherFoos WHERE ao.id = ?1", AbstractObject.class)
Problem: I got a nullPointerException because, I think, hibernate does not know foos or otherFoos for AbstractObject.
In my point of view, I do not know if I will have a ObjectA or ObjectB.
Do someone know a solution for this issue ?
Hibernate version : 5.0.12.Final

In general, in order to execute an HQL query and return properties of multiple entities on the same result, you need a projection to a DTO.
So you will create a DTO for example ObjectAB, which will not be mapped, it will probably extending both Object A and B and then you will create your query and set a result transformer to this DTO.
Alternatively you could use a Tuple instead of a DTO, but this doesn't change the main idea. For more details of this methodology you may read this article.

Related

Spring Data Neo4j Cypher get entity type or class name

In my SDN 4 project I have a following Cypher query(a part of query):
(entity)<-[:COMMENTED_ON]-(comg:CommentGroup)
for example I can get id of entity with a following Cypher function id(entity)
How to get entity name or class name ?
Use the labels function
match (entity)<-[:COMMENTED_ON]-(comg:CommentGroup) return id(entity), labels(entity)
For each row returned, you'll get the Neo4j id and array of labels.
Assuming your NodeEntity class labels match at least one of these labels, you can then iterate and load the appropriate class instance yourself.
Generally speaking you shouldn't need to do this however.
If (entity) is polymorphic, SDN/OGM will hydrate the correct objects for you. It pretty much does under the hood what I described above, but it also handles matching on interfaces, subclasses, etc.

AliasToBean DTO with known type

All the examples I am finding for using the AliasToBean transformer use the sessions CreateSqlQuery method rather than the CreateQuery method. They also only return the basic value types, and not any object's of the existing mapped types.
I was hoping it would be possible that my DTO have a property of one of my mapped Domain objects, like below, but I am not getting traction. I get the following exception:
Could not find a setter for property '0' in class 'namespace.DtoClass'
My select looks like the following on my mapped classes (I have confirmed the mappings pull correctly):
SELECT
fcs.MeasurementPoint,
fcs.Form,
fcs.MeasurementPoint.IsUnscheduled as ""IsVisitUnscheduled"",
fcs.MultipleEntryAllowed
FROM FormCollectionSchedule fcs
My end query will be more complex, but I wanted to confirm if this AliasToBean method can return mapped domain objects as well as basic field values from tables retrieved via sql.
the query execution looks like the following:
var result = session.CreateQuery(hqlQuery.ToString())
.SetResultTransformer(NHibernate.Transform.Transformers.AliasToBean(typeof (VisitFormCollectionResult)))
.List<VisitFormCollectionResult>();
note: the VisitFormCollectionResult DTO has more properties, but I wanted to know if I could populate the domain object properties matching the names
update found my problem! I have to explicitly alias each of the fields. once I added an alias, even though the member property on the class matched my DTO's property name, the hydration of the object worked correctly.
The answer to my own question was that each of the individual fields in the select needed an explicit alias matching the property, regardless if the field name already matched the property name of the DTO object:
SELECT
fcs.MeasurementPoint as "MeasurementPoint",
fcs.Form as "Form",
fcs.MeasurementPoint.IsUnscheduled as "IsVisitUnscheduled",
fcs.MultipleEntryAllowed as "MultipleEntryAllowed"
FROM FormCollectionSchedule fcs

CF9 ORM Populating an entity with an object

I am using Model-Glue/Coldspring for a new application and I thought I would throw CF9 ORM into the mix.
The only issue I am having right now is with populating an entity with an object. More or less the code below verifies that only one username can exist. There is some other logic that is not displayed.
My first thought was to using something like this:
var entity = entityload('UserAccount' ,{UserName=arguments.UserAccount.getUserName()},"true")
entity = arguments.UserAccount;
How ever this does not work the way that I expected. Is it even possible to populate an entity with an object or do I need to use the setters?
Not sure if this is what you're looking for. If you have...
component persistent="true" entityName="Foo"
{
property a;
property b;
}
You can pass a struct in the 2nd param to init the entity (added in CF9.0.1 I believe)
EntityNew("Foo", {a="1",b="2"});
To populate Foo with another object, you can use the Memento pattern, and implement a GetMemento() function to your object that returns a struct of all its properties.
EntityNew("Foo", bar.getMemento());
However, CF does NOT call your custom setters! If you want to set them using setters, you may add calls to the setters in your init() constructor, or use your MVC framework of choice to populate the bean. In Model-Glue, it is makeEventBean().
Update: Or... Here's hack...
EntityNew("Foo", DeserializeJSON(SerializeJSON(valueObject)));
Use this at your own risk. JSON might do weird things to your numbers and the 'yes','no','true','false' strings. :)
Is it even possible to populate an entity with an object or do I need to use the setters?
If you mean "Is it possible to create load an ORM Entity from an instance of that persistent CFC that already exists and has properties set?", then yes you can using EntityLoadByExample( object,[unique] )
entity = EntityLoadByExample( arguments.userAccount,true );
This assumes the userAccount CFC has been defined as persistent, and its username value has been set before being passed in (which seems to be the case in your situation).
Bear in mind that if any other properties have been set in the object you are passing, including empty strings, they will be used as filters to load the entity, so if they do not exactly match a record in your database, nothing will be loaded.

NHibernate Component mapping (Creating Criteria)

Is there any way to create an “alias” for a component?
I have a “Criteria Builder” that takes strings in the format of “Address.City” (or “User.Address.City”, …) and creates an ICriteria (filters and sorts) based on it.
I am using components to map the “Address” class so it stays in the same table as “User”.
The exception I am getting is:
NHibernate.QueryExceptioncould not resolve property: City of: MyNamespace.User
If I attempt to do not create an “alias” for the Address Component, it works just fine.
However, as it is a criteria builder, is there a way to detect that “Address” is a component and avoid the call criteria.CreateAlias(“Address”)? Any work around?
This is the same question as mine, however the solution is not viable to me (I do not create criteria manually for each query).
Any help would be much appreciated!
You can't create an Alias for Address because Address is not a mapped entity. The only difference between CreateAlias and CreateCriteria is that the former returns the original Criteria, whereas the latter returns the new Subcriteria. So the only classes you can create Criteria for are classes that have been mapped. Since components are not mapped classes, you can't create a criteria around them.
The only suggestion I have is to have your Address class either to implement an empty descriptor interface like IComponent or mark it with a custom ComponentAttribute. Then your CriteriaBuilder can check whether or not the class it's creating a criteria for has this meta data and ignore it.

Cast an IList to an IList<t> using dynamic instantiation

I am try to convert the following NHibernate query using dyanmic instantiation into an IList<t> rather than an IList.
IList<AllName> allNames =
(IList<AllName>)Session.CreateQuery(
#"select new AllName(
name.NameId, name.FirstName, origin.OriginId, origin.Description,
name.Sex, name.Description, name.SoundEx
) from Name name join name.Origin origin")
.SetFirstResult(skip)
.SetMaxResults(pageSize);
Running this I get the following error:-
Unable to cast object of type
'NHibernate.Impl.QueryImpl' to type
'System.Collections.Generic.IList`1[Domain.Model.Entities.AllName]'.
I know that I can return
IList results = Sesssion.CreateQuery(...
but my service layers expect an
IList<AllName>
How can I achieve this?
One option would be to write an IList<T> implementation which proxies to an IList, casting where appropriate. It shouldn't be too hard to do, albeit somewhat tedious. LINQ will make this slightly easier in terms of implementing IEnumerable<T> etc - you can just call the underlying iterator and call Cast<T>() on it, for example.
Another solution would be to create a new List<T> from the returned list:
IList query = Session.CreateQuery(...);
IList<AllName> allNames = new List<AllName>(query.Cast<AllName>());
EDIT: As Sander so rightly points out, this is what ToList is for:
IList query = Session.CreateQuery(...);
return query.Cast<AllName>().ToList();
EDIT: All of this has been NHibernate-agnostic, as it were - I don't actually know much about NHibernate. Rippo has now found a much simpler answer - call List<AllName> instead (which is an NHibernate method).