Hi,
I made a custom IResultTransformer to be able to do
something like this (hopefully this is not duplicated efforts ;) ):
Code:
DetachedCriteria c = DetachedCriteria.For(typeof(Entity),"root")
.Add(Expression.Eq("root.Id",42)
.CreateAlias("SomeAssociation","s")
.CreateAlias("BagOfTricks","tricks")
.SetProjection(Projections.ProjectionList()
.Add(Property.ForName("root.Id").As("Id"))
.Add(Property.ForName("s.Name").As("SomeObject.Name"))
.Add(Property.ForName("s.Name").As("SomeObject.Child.Name"))
.Add(Property.ForName("s.Name").As("SomeObject.Child.Child.Name"))
.Add(Property.ForName("tricks.Id").As("Tricks.Id"))
.Add(Property.ForName("tricks.Name").As("Tricks.Name"))
.Add(Property.ForName("tricks.Name").As("Tricks.Child.Name"))
.Add(Property.ForName("tricks.Name").As("Tricks.Child.Child.Name"))
.Add(Property.ForName("tricks.Name").As("Tricks.Child.Child.Child.Name"))
)
.SetResultSetTransformer(new DeepObjectGraphTransformer(typeof(DeepDTO)));
IList<DeepDTO> dtos = c.GetExecutableCriteria(session).List<DeepDTO>();
//Fills the following imaginary Unmapped model
public class DeepDTO
{
public int Id {...}
public DTOChild SomeObject {...}
public IList<Trick> Tricks { ... }
}
public class DTOChild
{
public string Name { ... }
public DTOChild Child { ... }
}
public class Trick
{
public int Id { ... }
public string Name { ... }
public DTOChild Child { ... }
}
The basic tests are passing.
Now, I spent much more time on trying to find out
if I could get NHibernate's Criteria API projections to
return deep object graphs out-of-the-box, than I spent writing the IResultTransfomer.
The transformer is a clone of the AliasToBeanResultTransformer.
The transformer parses the alias notation and sends aliases which look like child associations
recursively to a new instance of the same implementation with the subset of tuples
and aliases belonging to the child association. That was easy ;)
Also, it looks for properties of type IList<T> and handles them by sending the type of T, a subset of tuples, and a subset of
aliases recursively to a new a instance of the same implementation again and then adding the resulting object to the list.
The flattened hierarchy is then processed in TransformList the same way the DistinctRootEntity transformer
does, and the IList<T> properties are merged to the one and only root-instance in a post-process.
Before I wrote the IResultTransfomer I tried to fetch the results with HQL projections
and manually transforming the Tuples to the specific DTO, but I felt falling back to
oldschool world of recordsets...
Before I dive any deeper into testing the transformer with different models, I would really like to ask if there is
no easier way to fill unmapped objects with child associations and collections with
projections ?
Basically, what I would like to do is to run Queries against the mapped Domain Model
(because the queries are somewhat more domain specific because of the usage of the domain's concepts),
and to return lighter weight unmapped objects in certain scenarios. And especially I would
like to use the Criteria API for this.
Now, is this possible by using some other way than Projections and ResultTransformers, or
is a custom IResultTransformer the way to go ??
Suggestions ?
Thanks,
Janne