Thursday, June 9, 2011

ActiveReports: Grouping

We've used Grape City's (formerly Data Dynamics) ActiveReports off and on for many years. I'm not truly a fan since personally I've never found it that intuitive, but for flexibility they're pretty good.

Recently I ran into a quirk I've encountered before but had forgotten. I won't call it a bug since we're using it in a manner that is undocumented and most likely not supported.

Since AR uses (or appears to use) DataBinder.Eval to evaluate the DataField on each object in the DataSource of a report, we have always used collections of domain objects for our report sources. This works well for textboxes, however, when you try to do a standard report grouping (with header and footer) you'll get stuck wondering why the report only seems to recognize one group. Specifically this occurs when you use a property path of depth greater than one.

The following works:
myTextbox.DataField = "Property1.Property2";
myGroupheader.DataField = "Property1";
This does not:
myTextbox.DataField = "Property1.Property2";
myGroupheader.DataField = "Property1.Property2";
The textbox will populate correctly but the report will only discover one group of records.

Friday, May 6, 2011

NHibernate: Group By Case Statement

Today I wanted to speed up some statistics tables which had been tossed into our application dashboard awhile back. The queries were originally written quick and dirty to just pull back all of the records in the table then run some linq counts on them. Terrible of course and there was a nice little comment above the section saying something about "TODO: make this better".

The quickest query I could think of to run these statistics looks something like this:
select 
IsJourneyman,
case when Accepted is null then 1 else 0 end,
Count(*)
from
students
group by
IsJourneyman,
case when Accepted is null then 1 else 0 end
My next thought was "Can I implement this in ICriteria?" Well it turns out the answer is Yes!
var cr = Session.CreateCriteria<Student>();

cr.SetProjection(Projections.ProjectionList()
.Add(Projections.RowCount(), "Count")
.Add(Projections.Group<Student>(s => s.IsJourneyman), "IsJourneyman")
.Add(Projections.GroupProperty(
Projections.SqlProjection("case when Accepted is null then 1 else 0 end",
new[] { "IsApplicant" }, new[] { NHibernateUtil.Boolean })),
"IsApplicant")
);

// transform the results into a strong typed object
cr.SetTransformer(Transformers.AliasToBean(typeof(CountResult)));

return cr.List<CountResult>();
For which I created this simple class. The aliases passed to .Add() are used to match up the properties.
public class CountResult
{
public bool IsJourneyman { get; set; }
public bool IsApplicant { get; set; }
public int Count { get; set; }
}
I tried using the Projections.Conditional, but ran into a NHibernate bug on mixing named and ordered parameters.

I'm sure there are faster ways to accomplish this, but since I wanted to do it in NHibernate without adding a calculated field this will work for me.

Thursday, April 21, 2011

Free Reflector Alternatives

If you're like me you were super disappointed when Red Gate reneged on their promise to keep .Net Reflector "free forever". While I don't use Reflector every day, there are numerous times where I've needed to drill into a dll to see how something is accomplished or find some functionality I need.

Fortunately, there are new alternatives appearing for us penny pinchers. Hopefully Red Gate will get the message.

ILSpy - ILSpy is a free, open source replacement for .Net Reflector. Look and feel are modeled on Reflector.

JustDecompile (h/t Assia) - Telerik's foray into the market. Currently in beta but promises regular updates and an integrated auto-updater.

dotPeek - By JetBrains.