Saturday, November 20, 2010

SiteCore 6.4

SiteCore is a great .NET-based CMS.

I've seen so many CMS's, I'm frankly sick of them. Give me something useful and new. Hello, SiteCore. It's definitely better than Kentico, Umbraco, DotNetPuke, Sharepoint (ok not just a CMS but hey), OBS and even the legendary Pile of Code.

The Online Marketing Suite is the icing in the cake. I was in an OMS training day a few weeks ago and I thoroughly enjoyed it. Instrument your code; watch the marketing people have orgasms. Great stuff.

Thing is, the latest version 6.4 is still not going to *properly* support MVC or .NET 4. MVC I'm still out on; yes I know Model-View-Controller is a great pattern, not sure ASP.NET's version is that good though.

ASP.NET 4 WebForms is superb - please read this if you're not up to speed on the many new features it offers. Most ASP.NET developers are WebForms based, and MVC is a big paradigm shift for them. I know it allows a greater testing surface, amongst other benefits, but if you're doing your job properly and maybe following an MVP pattern in your web applications, then why switch ?

I think SiteCore have a fight on their hands; open-source competitors are going to eat into their share if they can't provide up to date development models, and frankly their licensing takes the piss. They want to charge us for staging licenses. Like.. what ??? Get bent guys..

The real question. Is Orchard the new messiah, or just a very naughty boy ?

Monday, November 8, 2010

nHibernate 3.0 QueryOver - Searching, and Paging at database level

I've been through numerous data-access technologies with .NET - plain old DataReaders & SqlCommands, Code-genned layers around these of various descriptions and varying degrees of horrible, Pile of Code, Typed Datasets, Linq-to-SQL, Lightspeed, LLBLGen Pro, Entity Failwork.

Of all these, nHibernate 3.0 is definitely one of them. No doubt something better is on the horizon and when it looms into view I might take a look. Until then, this is working well for me.

In my humble opinion, NH3 is way better than Linq-to-Fail or infact any other model-based ORF (Object-Relational Failfactory).
  1. The fluent style works well; it's nice to use
  2. It's codegen-able like a crazy thing
  3. It's flexible and very extensible
  4. It performs - the generated SQL is lean and exactly what you need, it's measurably faster than L2S or Lightspeed
  5. It isn't Linq-to-SQL
  6. or a cabbage
NH3 gives us a whole set of functionality missing from 2.1 - functions that wrap typical SQL functions. It also gives us a lot of additional flexibility with lambda's prevalent over magic strings, so refactoring and catching problems at design time is now a doddle.

That said, I'd like a nicer way of doing multi-field searches; maybe by using an Expression<ICriteria> as a parameter to my search method ?

Here is my search method, abbreviated so as not to cause boredom: -

public IList CustomerSearch(CustomerSearchCriteria criteria, int pageIndex, int pageSize)
            IList list = null;

            using (var session = SessionFactory.OpenSession())
                var query = session.QueryOver();

                if (!string.IsNullOrEmpty(criteria.CustomerName))
                    MatchMode matchMode;
                    if (criteria.CustomerSearch == CustomerSearchEnum.StartingWith)
                        matchMode = MatchMode.Start;
                    else if ..
                    // etc

                    query = query.WhereRestrictionOn(x => x.CustomerName.ToLower()).IsLike(criteria.CustomerName.ToLower(), matchMode);
                if (criteria.ActiveOnly)
                    query = query.And(x => x.Active == true);
                if (!string.IsNullOrEmpty(criteria.Address1))
                    query = query.And(x => x.Address1.ToLower().StartsWith(criteria.Address1.ToLower()));
                // etc

I'm working on a nicer way of doing this, so stay tuned. That said, the above is fairly readable; I'm just appending additional sections to the WHERE clause where needed.

Hmm.. Anyway, one thing NH3 gives us is database-level paging using the SQL Server ROW_NUMBER function, which is efficient (much more efficient than selecting the whole set into memory and doing the paging there..).

list = query.Skip(pageIndex * pageSize)
    .OrderBy(x => x.CustomerName).Asc()

This is nice, except it *only* returns the rows in the page. How do I know how many rows there are in total, so I can set up my pager accordingly ?

This is easy when done at stored procedure level, as I can just run an additional Count(*) SELECT and return an OUT parameter, all in one hit to the database. Am I going to need two hits here ?

As it turns out, the CriteriaTransformer has a "TransformToRowCount" method, which does what we need. This does issue one more SQL statement for the count, and it's submitted separately - so two round trips, not ideal.

list = query.Skip(pageIndex * pageSize)
    .OrderBy(x => x.CustomerName).Asc()

int count = CriteriaTransformer.TransformToRowCount(query.UnderlyingCriteria)

And after reading this, the process has been simplified even further with the addition of an extension method. So the previous example can be re-written as just ..

list = query.Skip(pageIndex * pageSize)
    .OrderBy(x => x.CustomerName).Asc()

int count = query.RowCount();

Nice ! But still two database hits. There are two ways to fix this: -
  1. Use a transaction
  2. Use a projection
I'll write some drivel about projections at a later date.


StructureMap usefulness

Yet again I find myself spending literally minutes of my life trying to figure out why something is going wrong, only to find a useful feature of something that could potentially save many more minutes; time better spent writing unit tests, for example, or lolling around the coffee shop talking about stuff.

Turns out in the end I'd configured the wrong repository name. Dumbass mistake of the kind we all make from time to time, but one of those cases where the wood is clouding the view of the trees in the way woods always seem to.

I'd done this ..

instead of this..

Note "EmployeeRepository" instead of "LookupRepository". For clarification, LookupRepository wasn't yet finished.

Upon trying to resolve a reference to IEmployeeService, StructureMap was throwing Exception code 202 - "No Default Instance defined for PluginFamily IEmployeeRepository". Confusing at first, turns out I was of course staring at the obvious problem all along.

Trying to replicate this was a pain as it was a case of fire up unit test; get to point that fails; fail (repeat).

Now I'm sure you've come across the ObjectFactory's "WhatDoIHave" method - which dumps out the state of the container, and what resolves to what. It's a useful way of pinpointing anything that doesn't have a concrete type defined for resolution. However, this chap is even more useful: -

Rather than having to get to the GetInstance method of StructureMap to find out you have a configuration problem, you can instead call this after ObjectFactory.Initialize, and it'll run through the map and attempt to construct everything it can.

I wouldn't recommend this for production release, but while in build it could save you at least one cup of coffee. And that's a good thing.

StructureMap is great. So much nicer to use than Unity. Feeling the love :o)