Monday, July 25, 2016

Gentlemen! (m/f) – Restart your View Engines!

Take real advantage of the MVC pattern and step, with me, outside of the box for a minute.

So here’s the thing. I’ve been doing Sitecore implementations for over 10 years now. And for all of those 10 years, part of my job has been – to some extent – taking front end assets (HTML, JS and whatnot) delivered to “the project” by either an external agency or internal team and work it into the Sitecore solution.

You all know the deal; you take these HTML files, you break them into their component parts by chasing down <DIV> elements. Lately, you may have noticed that you often get the HTML delivered in part like this already – so broken down “library” snippets of HTML. Be that as it may, you still end up having to “Sitecoreify” this into your solution.

You replace the static text and images with Sitecore Controls (if you’re still stuck with Webforms) or maybe Sitecore Razor helpers (@Html().Sitecore.Field(“Headline”)). Or maybe you’re using Glass to wiff things up a bit, or perhaps you’re in the same camp as I am, believing the Razor view should depend on nothing but the model – so you end up with code like FieldRender.Render() into your model properties.

Whatever your approach, I think we’ve all been down one or more of these roads.

What If I Told You - what if I told you All of that work is obsolete

Yep. Morpheus isn’t wrong. I’ll elaborate.

What if I told you – you could achieve all of this:

  • Never mess around with another View file again. You’re a Sitecore rockstar, why would you be spending your time on trying to inject “col-md-40” class attributes into frontend elements when you could be spending your time on better eXperience Editor support?
  • Not to mention; having to inject class attributes based on back-end functionality and data just feels oh so n-tier-wrong to begin with.
  • Remove anywhere from 20% to 50% of your Sitecore project implementation time.
  • Remove anywhere from 20% to 50% of your Sitecore project implementation time. I repeated this on purpose. Try measuring your own time, spent on fiddling with views.
  • Achieve complete separation of frontend and backend parts of your project. The “No man’s land” that currently exists somewhere in the .cshtml space can be eliminated.
  • Your frontend developers would never need to leave their OSX Macbooks and boot up Windows.
  • Get people working on what they do best; instead of having to require people on your team with skillsets that look like this:
    • Must know c#, javascript, handlebars, Sitecore, SQL, SQL Replication, MongoDB, SOLR, Lucene, ASP.NET MVC, CSS, Responsive Design, Photoshop, NodeJS, jQuery, jQuery UI, Bootstrap, Knockout and how to fish.
  • When instead these concerns should be (and almost without exception always are, in the real world) separated:
    • C#, Sitecore, ASP.NET MVC (Sitecore Developers)
    • Javascript, Handlebars, CSS, Responsive Design, NodeJS, jQuery, jQuery UI, Bootstrap, Knockout (Frontend Developers)
    • SQL, SQL Replication, MongoDB, SOLR, Lucene (Application Engineers)
    • Who fishes, anyway?
  • Get “backend” developers (Sitecore) working on what they do best. Model Sitecore, set up IA, implement features – present it all in the form of Models. (M).
  • Get “frontend” developers working on what they do best. Handlebars, frontify, node, SASS and so on – anything and everything that runs on the client – and feed their Views (V) with a mock of the Model (M).
  • Connect the two worlds with Controllers to render the final results server-side and send it off to whatever client happens to be connected (C).

Have I got your attention yet?

This is how we do-o-o it

Admit it, I now managed to get that song spinning in your mind. Don’t worry, it will go away in a couple of hours ;-)

So yea. The technology exists. I’ve been hinting at it for a while, some documentation and explanation effort is underway. I hope to find time to aid in some of this documentation and explanation effort as well – but for right here and now, my aim for this post is just to serve as an eye opener, thought provoker, and see if I can get a bit more community engagement going.

What I’m on about is NitroNet for Sitecore.

NitroNet for Sitecore in less than 5 minutes.

Don’t worry if most (or all) of the below Open Source projects I mention now are completely unknown to you. If you are like me, you probably know as little about the whole frontend developer stack as you can get away with – and it is exactly this stack that NitroNet for Sitecore aims to bridge the gap to. Stay with me.

NitroNet for Sitecore is an extension to NitroNet. It adds Sitecore concepts to the stack, in form of placeholders, eXperience Editor support and so on.

What is NitroNet?

NitroNet is an ASP.NET MVC View Engine that replaces Razor. It parses Handlebars.js templates (server side), based on OS code from TerrificNet and Chris Sainty’s Veil Engine.

So in simpletalk: NitroNet replaces Razor to do Handlebars server side instead of Razor Views.

(but you can still use Razor Views, should you need to)

NitroNet is the server side component for Nitro.

What is Nitro?

Frontend developer framework. I’m actually not being vague intentionally here, I simply don’t know all that many details LOL :D  But that’s the beauty here; I don’t need to know all that much about frontend – and I like it like that.

So here’s a few highlights. And remember; this stack is all your frontend developers will need to worry themselves about. They don’t need Windows, they don’t need a local Sitecore running.

  • 100% file based
  • Runs on Mac, Win and Linux (and who knows, maybe more)
  • Encourages Atomic Design and BEM concepts
  • Comes with its own lightweight web server

So essentially, frontend developers will be “doing their thing” on their beloved Macbooks, developing components using Atomic Design/BEM via Handlebars, running and testing it locally and when they’re done they will even tell you (the Sitecore developer) what the model they require, looks like. All you need to do, is deliver it.

Take a look here, for more information. Better yet, point your resident frontend developer team in this direction and hear their thoughts: https://github.com/namics/generator-nitro/blob/master/app/templates/project/docs/nitro.md

So ummm….

Yea I know. Scope of this goes a little beyond “should we use this or that Dynamic Placeholder solution in our project?”.

I tell you this though; this is what real architecture looks like. In my view. Separation of frontend and backend concerns is key for a list of reasons so long, I wouldn’t even know where to begin. I challenge you to consider these things:

  • Having your frontend and backend developers being able to work in complete parallel – all they need to discuss early on, is the Model.
  • Having your frontend developers work on their tools and platform of choice, not needing to get them running Sitecore locally or even boot up Windows.
  • This goes for post go-live changes too. If the model doesn’t change, no Sitecore resource need even be involved in a fix.
  • 100% file based JSON models also means, you could hook into the Sitecore PathFinder project and possibly get your Sitecore templates, Rendering items and so on auto-generated. I’ll gladly get involved if a community effort is kicked up around this.
  • Completely removing the need for Sitecore developers to fiddle around with view files, hiding HTML blocks, injecting attributes, wasting their time. Sitecore devs don’t really come cheap, nor in particular abundance.

So yea. The scope of this certainly promises more than adequate ROI. I encourage you to verify my claim on this :-)

Quick list of links and references:

Start your engines!

Thursday, June 02, 2016

Decennial Series #3 – Sitecore.Context is an anti-pattern

And I’ll even attempt to tell you why

If you’re in any way or form following trends for “normal” development (should such a thing exist), you will no doubt have come across one or both of these terms:

  • Inversion of Control
  • Dependency Injection

You might even know what they mean. And why these terms are so popular these days.

Or you might not. But you’re implementing code following these principles anyway. Because your boss, team lead, customer, client or girlfriend demands that you do.

Either way, I’ll just do a very quick explanation of what these mean. If you know enough about these terms to tell me I’m oversimplifying this, this introduction wasn’t meant for you anyway. Skip to the good stuff further down.

IOC and DI in less than 5 minutes

Inversion of Control

Inversion of Control (IoC from here on) is the principle, that nothing in your system should make decisions on exactly which other systems to “talk” to. So your CustomerManager class shouldn’t really get to decide, it wants to talk to a SqlCustomerProvider. Your BasketController shouldn’t really get to decide, everything should be stored in HttpContext.Current.Session.

And why is that?

Because things change. They change over time, as customer requirements change. Someone might later want those BasketItems stored in a back-end Sql table so the Basket isn’t lost between user visits to your site. Someone might not want to pay good money for a Sql Server license to store only 200 customers.

Things change, is my point. And we’re trying to write software to best accommodate that.

But how can I write my BasketController if I can’t store my BasketItems anywhere?

But you can. And in writing it, you do obviously get to decide WHAT you require in order to store and retrieve your BasketItems. You just don’t write the actual implementation. You produce a “blueprint” of the requirements you have.

In C#, we call this an “Interface”.

So in short (simple) summary. Inversion of Control (IoC).

You might have started out like this:

public class BasketController
{
    private readonly BasketStorage _bs;

    public BasketController()
    {
        _bs = new BasketStorage();
    }

    public List<BasketItem> GetBasket(int customerId)
    {
        return _bs.GetBasket(customerId).ToList();
    }

    public void StoreBasket(int customerId, IEnumerable<BasketItem> items)
    {
        _bs.StoreBasket(customerId, items);
    }
}

So what’s the big deal?   Well it’s about control. You might argue; “so what if the client changes her mind, and wants this to come from Sql instead of Session?  I’ll just make a new BasketStorage class, job done”.

And you’re right of course.

But what about me?  the consumer of your API?   or me, the maintenance developer who – 3 years from now – actually want to do both?  Store BasketItems in SessionState – and then persist them to Sql when Session expires?  Why can’t I be your friend?

I’m the consumer of this API, and it’s not unreasonable that I have some form of control over these matters.

So the way we both get happy, is find common ground. With just a little tweaking (and tools like Resharper does like 95% of this work for you anyway; go ask your boss for a license), we can both win. You still get to easily replace one BasketStorage for another, and I get a choice in the matter too.

So we (you, actually) make up the blueprint. The Interface.

public interface IBasketStorage
{
    void StoreBasket(int customerId, IEnumerable<BasketItem> items);
    IEnumerable<BasketItem> GetBasket(int customerId);
}

And you apply this to your existing BasketStorage class.

public class BasketStorage : IBasketStorage
{
    public void StoreBasket(int customerId, IEnumerable<BasketItem> items)
    {
        throw new NotImplementedException();
    }

    public IEnumerable<BasketItem> GetBasket(int customerId)
    {
        throw new NotImplementedException();
    }
}

(and you finish up the methods that I am too lazy to flesh out in this blogpost, naturally)

So far, this is a matter of maybe 20 keystrokes and a few Resharper tricks. And you’re almost done. One last thing.

private readonly IBasketStorage _bs;

public BasketController(IBasketStorage bs)
{
    _bs = bs;
}

And that’s it. You’ve now achieved IoC with Dependency Injection (DI). Well done you.

“But instead of having just 1 place in my code where I created my BasketStorage() class, I am now forced to spread it out everywhere in my codebase!?!?   SURELY that cannot be better?”

And you’re right indeed. Enter: The Service Locator. Notice how I made the person next to you just spill coffee?

How are we for time?  got a couple of minutes before the 5 minutes are up, yea?

Service Locator, also in very short and simple terms.

If you’ve heard the terms IoC and DI, you have absolutely also heard someone – at one point or another – mention “Service Locator is an Anti-Pattern”.

And it can be. Indeed. But let me also tell you…   somewhere in your system, SOMEONE is going to have to instantiate some classes and services at some point. And they are going to need to locate these classes and services. Stay with me on this. We’ll get through this, you and I.

The most direct way to go about, getting these dependencies injected – is to use the Service Locator Pattern. It looks like this:

var basketStorage = DependencyResolver.Current.GetService<IBasketStorage>();
var basketController = new BasketController(basketStorage);

Or the slightly better version:

var basketController = DependencyResolver.Current.GetService<BasketController>();

Notice how, in this last example, we don’t even worry about IBasketStorage any longer. The DependencyResolver is meant to work this out (almost) on it’s own.

“But how does it know?”

Yea, I skipped that didn’t I?  I don’t really want to make this post about, how DI frameworks are configured. In Castle Windsor, it looks like this:

container.Register(Component.For<IBasketStorage>().ImplementedBy<BasketStorage>());

So now, whenever someone requests (registers a dependency for, usually in the class constructor) IBasketStorage, the DependencyResolver knows to instantiate BasketStorage() and send that off to the requesting class.

Just for reference, this form of DI we call “constructor injection” for hopefully obvious reasons.

I think our 5 minutes are up. So let’s address the elephant in the room; “Why is this an Anti-Pattern then?”.

Service Locator and the bad rep

It’s not so bad. Really. Not when used like I just showed here. But that’s not to say, you can’t get in a lot of trouble using SLOC. You absolutely can. Let’s return to the example from before. Imagine I had done it like this:

private readonly IBasketStorage _bs;

public BasketController()
{
    _bs = DependencyResolver.Current.GetService<IBasketStorage>();
}

Same thing, right?  Except now, my BasketController() is nice and easy to instantiate again.

Wrong.

First of all, you’ve now come full circle and achieved exactly nothing. You’ve pushed an interface down on top of BasketStorage, good on you. But to what end?

Dependencies are no longer injected, so DI is out. As for control. Well it’s still somewhat inverted at least – but it’s well hidden from my view. Me, the API consumer/maintenance developer/ravaging psychopath who knows where you live.

So when I, 3 years from now, go… “oh, I’m gonna use this fancy BasketController. Public constructor, no dependencies. I’ll just add 1.000.000 to customerId, and we can use it to store the Wishlish for the customer – I’m a genious. Long weekend, here I come. We’re in an HttpModule with no SessionState, but why should that matter?”. And I go:

var bc = new BasketController();
bc.StoreBasket(1000000+customerId, wishlist);

Yay me. Except. Noooooo. YSOD.

What happened?  Well I didn’t know, invoking BasketController called out using SLOC and procured IBasketStorage. I probably didn’t even know that IBasketStorage required SessionState – but as I said, I didn’t even know about the requirement for it in the first place.

And that, is the problem with the Service Locator.

It hides dependencies. It’s (sort of) IoC but without DI. It’s Prince without The NPG. It’s Bonnie without Clyde.

It’s just not really very good. That’s what I’m saying.

The Good Stuff

I told you this was coming yea?

So as I might have let shine through a little; I do come across zealots from time to time who will turn into an absolute jumblepot of failed arguments and internet quotes whenever I even dare mention the unspeakable Service Locator. “Everybody KNOWS it’s an Anti-Pattern.” (you know who you are).

The irony is, in our day to day work with Sitecore, you (not me) use the Service Locator Pattern ALL THE TIME. Hundreds and hundreds of times every day. Often these very same zealots use it, some of them aren’t even aware.

Take a look at this:

var database = DependencyResolver.Current.GetService<Database>();
var database = Sitecore.Context.Database;

If you think there is anything other than just a semantic difference between those two lines of code, you’ve missed a point somewhere. Start over from the top of this article.

Sitecore.Context is a Service Locator

Actually, I’ll work the font a little and repeat.

Sitecore.Context is a Service Locator

And it has ALL the problems of a Service Locator, too. All of them.

Ever tried calling some of your code – say some Url Generation code – only to find it blows up when called from a Sitecore Publishing Processor?  Sitecore.Context.Site is NOT what you expect is it? 

Or called some Sitecore code from a Unit Test?   I tell you; BOOKS have been written to explain to you why this will blow up. Hint: It’s mostly to do with Sitecore.Context.Database.

Sitecore – in pretty much every corner and crack you look into, has services and functions that rely on other Sitecore services and functions. It is all hidden from view (although some, very far from all, is exposed in the configs), and unless you have lots and lots of Sitecore experience, predicting what calling Sitecore.Context.Database is actually going to need is near impossible.

There is little to no runtime DI in play anywhere; and the config files only allow you to really alter some of the dependencies on a very top level.

And you know what?  this is fine.  Well no it’s not – but it is what it is. If this ever changes, I am almost willing to bet a Dollar, Sitecore will roll out a NEW API to live side-by-side with the existing one. But let’s leave this for now and get to the punchline.

Every time you use Sitecore.Context (or RenderingContext.Current or pretty much any global static in the Sitecore API) – you are using the Service Locator Pattern. And it gives you all the problems that got it labelled as an Anti-Pattern to begin with.

I’m not saying you can avoid it, really. While there are ways to work around most of it; in some cases you just have to cease fire and accept the way things are.

But I’m saying you can:

  • Be aware of it
    • Awareness of a problem is often the first step in minimizing the impact, the problem will have on your project
  • Minimize the use of it
    • Declare your dependencies. Even if you can’t fix all of it; demand “SiteContext context, Database database” in your constructor if you’re going to use them. At least bring back DI.

Over time, this becomes second nature to you. You no longer get mysterious yellow screens because your context is not what you expect. You no longer increase the workload of your poor maintenance programmer by 100-fold, trying to work out what external dependencies your code has (generating a Product Url requires a Site Context, a Context Database, a Context Language, a Context Item and your SSN – seems fair, right? – real story btw, except for the SSN).

Now let’s get back to work.

Wednesday, May 18, 2016

Setup Castle Windsor for Sitecore 8.1 in 5 easy steps

Getting started with Dependency Injection is easier than you think

So I was reading Kevin Obee (@KevinObee) write about Dependency Injection, and how many of you out there wasn’t using it yet. While the post that inspired me addresses Webforms implementations, I also find this lacking in many MVC solutions I come across.

Further; most of the examples you find on the web now – setting up DI for Sitecore – is obsolete as of Sitecore 8.1. These days, it’s much much easier than it used to be.

I’m going to demonstrate using Castle Windsor as my DI container. Personal preference, I’m sure there are similar ways of doing it with AutoFAC, SimpleInjector and whatever else roams about.

So let’s get to it.

Step 1 – Install packages

Start with a blank solution set up for MVC. Or use whatever you have on hand right now. Now get your NuGet going. We’re after the CommonServiceLocator.WindsorAdapter.

Via GUI

step-1_thumb1

or if  you prefer, via the Nuget Package Manager Console.

step-2_thumb2

 

Step 2 – Update packages

Do a few updates. Personal preference here, but registration options have improved a lot since the minimum version of Castle Windsor required for this to work.

step-3_thumb1

 

Step 3 – Write some code

But not a lot. Truly.

step-4_thumb2

IntelliSense… mostly a blessing, but sometimes a bit of a nag.

Step 4 – Line it up

Now we just need to wire this up. Sitecore Best Practice would be, to get this cooked up in the <initialize> pipeline. So let’s do that.

step-5_thumb1

Step 5 – Join us on Slack

Just kidding. You’re done. That’s it. I won’t go into detail on how to actually use Dependency Injection, there are plenty of good tutorials on the web for that.

Meanwhile I suggest you come on the Sitecore Slack Channel. You’ve got plenty of spare time on your hands now, I just showed you how to do a 1 day task in 5 minutes flat ;-)

If you’re feeling doubly lazy, I’ve created a Gist with the two files on display.

Sunday, May 08, 2016

Effective use of Sitecore LinkDatabase

Keep track of your Reference Field references

I’ve often mentioned the Sitecore LinkDatabase, which I’ve found to be a hugely useful resource over the years but it’s getting very little exposure. And given I need to test out the Open Source version of my favourite blogging tool, I figured I might as well hit 2 birds with 1 stone and write a post about it.

What is Sitecore LinkDatabase?

Sitecore LinkDatabase (to save my sanity, hereafter referred to as SLDB) is a simple table that keeps track of Reference Field references. And what are Reference Fields?   Basically anything that stores one or more IDs as the raw field value. So Droplink, Treelist, Image, Internal Link and so on.

SNAGHTML13175c1f

And raw values looking like this:

image

And this is where the SLDB comes into play. What it does, is keep track of those references. It basically stores something to the effect of; “Item {id} on Field {id} keeps a reference to Target Items {id}{id}{id}”.  The reasons this functionality exists, is to support the Sitecore Content Editor so that when you are about to delete an item that might be used elsewhere, it pops a warning.

image

In this case I am not given other choice (as I’m trying to delete a Template in use), but in other cases Sitecore will offer you to remove the references to the Item you’re about to delete, or relink the references to someplace else. As a side note; this, too, is immensely useful functionality if you’re refactoring your content – but that’s a story for a different day.

The nuts and bolts

Currently, the SLDB looks like this:

image

It sits in your “core” database. Be mindful of this if you’re going to be putting it to use – “core” may or may not be available in your Content Delivery environment depending on your setup. Easily fixed, however. Configuration for it sits here:

  <!-- LINK DATABASE -->
  <LinkDatabase type="Sitecore.Data.$(database).$(database)LinkDatabase, Sitecore.Kernel">
    <param connectionStringName="core" />
  </LinkDatabase>

Migrate the “Links” table from “core” to “web” or wherever you please, and you’re good to go.

The day to day is handled by this event handler, you’ll find it on most of the item events.

<handler type="Sitecore.Links.ItemEventHandler, Sitecore.Kernel" method="OnItemCopied" />

And there’s also a setting. Leave it at it’s default if you’re going to be using the SLDB at runtime (if you toggle this “off”, SLDB won’t be kept up to date for “web”).

<setting name="LinkDatabase.UpdateDuringPublish" value="true" />

Caveat: If you’re using the excellent Unicorn; be sure to allow it to update SLDB during sync operations. It is currently off by default. You need version 3.1.5 or later.

The nitty-gritty

Right, so enough. WHY should you care?  Well let me show you.

So I’ve set up a vanilla solution, and defined me some templates. It’s not particularly advanced, but it represents a pretty common IA challenge in our solutions today.

SNAGHTML134587f2

So we have a “News” template. It can exist in several categories, and has 1 Author.

IA challenge #1: We can’t organise “News” in category “folders”, as it is not a 1:1 relationship
IA challenge #2: We need news organised in a deep “folder” structure for SEO and performance

Using a bit of c# code so hacky I would never share it, I end up with 1000 “News” articles, with a random number of categories and so on.

image

I’ve kept the organisation simple, as this will be enough for what I’m trying to demonstrate.

image

So basically a “month” folder. In a real scenario, likely you would go 1 level deeper and include “year”. It won’t matter for this example however.

Now; our common problems with this are:

Problem #1: How do I list all “News” in a specific Category?
Problem #2: How do I list all “News” by a specific Author?

I’m going to pretend we live in a world where indexing this data isn’t an option, and we’re left with just the basic tools available to us.

Solution #1: Use Sitecore Query
Solution #2: Use Sitecore Fast Query
Solution #2: Use SLDB

Let’s see what that looks like. I cook up some rudimentary (and ugly) code:

var db = Factory.GetDatabase("web");
List<Item> authors = db.GetItem("/sitecore/content/Solution Data/Authors").GetChildren().ToArray().ToList();
List<Item> categories = db.GetItem("/sitecore/content/Solution Data/Categories").GetChildren().ToArray().ToList();
ID newsTemplateId = new ID("{5CB0FC6D-DCAA-4A51-8745-D9933F77679A}");
var newsRoot = db.GetItem("/sitecore/content/Home/news");

// Make sure Sitecore is warmed up
newsRoot.Axes.GetDescendants();

Response.Write("<h2>Authors</h2>");
var sw = new Stopwatch();
foreach (var author in authors)
{
    Response.Write($"<strong>{author.Name}</strong><br />");
    sw.Start();
    var referrers = GetAuthorReferrers(newsRoot, author.ID);
    sw.Stop();
    Response.Write(referrers.Length + " articles; Time in Ms: " + sw.ElapsedMilliseconds + "<hr />");
    sw.Reset();
}

And the most important bit, how I query it.

Regular Sitecore Query

Item[] GetAuthorReferrers(Item root, ID authorId)
{
    string query = root.Paths.FullPath + "//*[contains(@Author, '" + authorId + "')]";
    return root.Database.SelectItems(query);
}

I run this a couple of times (I’m not exactly in a stable environment to conduct any real scientific test of this – keep this in mind).

image

I then rewrite it for Sitecore Fast Query.

Sitecore Fast Query

BE AWARE!   Sitecore Fast Query sacrifices functionality to gain performance. Be especially aware of its limitations if your solution is multilingual.

Code now looks like this:

Item[] GetAuthorReferrers(Item root, ID authorId)
{
    string query = "fast:" + root.Paths.FullPath + "//*[@Author = '%" + authorId + "%']";
    return root.Database.SelectItems(query);
}

And an output that comes out like this. (Believe me, I ran this dozens of times).

image

Are we having fun yet?  I can offer up a bit of speculation on what’s going on here, but I’m honestly not completely sure. Mostly because I would never use neither solution to query my data, so my experience is somewhat limited. My best guess would be; to benefit from fast: query, you need more data. I will try this out with a larger dataset a bit further down.

So anyway. Roll on SLDB.

Sitecore LinkDatabase

Drawback of this approach is, that it’s a bit more code heavy. Not by much though.

Item[] GetAuthorReferrers(Item root, Item author)
{
    ID authorFieldId = new ID("{438E45E5-9F85-4705-976E-FC76E563F5EF}");

    var items = new List<Item>();
    ItemLink[] itemLinks = Sitecore.Globals.LinkDatabase.GetItemReferrers(author, false);
    foreach (var il in itemLinks)
    {
        if (il.SourceDatabaseName.Equals(root.Database.Name) && il.SourceFieldID == authorFieldId)
        {
            items.Add(il.GetSourceItem());
        }
    }
    return items.ToArray();
}

And here’s how we end up.

image

Am I managing to convince you yet?   so far we’re doing ok. We’re outperforming Sitecore Query by about 10 to 1. And Sitecore Fast Query by 50 to 1. A pretty decent start I’d say.

The sleight of hand

So I’m left with two problems. I’ve not brought “Category” into play. And I’ve not got a simple output, that fully compares these 3 side by side. I’ve created a Gist with the full source code – it is to long to include here, even by my standards.

Enter, a code rewrite. This time I’m looping through all Categories, then all Authors – finding all News articles that match the Category AND the Author. It completes the setup, and it actually demonstrates one of the slightly more complex situations when using SLDB. Using querying this becomes just another “and” expression.

SLDB code looks like this:

private Item[] GetNewsArticlesSitecoreLinkDatabase(Item newsRoot, Item authorItem, Item categoryItem)
{
    // Note. SLDB version of this actually needs to make 2 lookups. First to find all news articles referencing our author, then all that reference the category.
    // Note #2: Still, my hand is not shaking ;-)

    var authorFieldId = new ID("{438E45E5-9F85-4705-976E-FC76E563F5EF}");
    var categoriesFieldId = new ID("{31D2A6CC-6984-4CA0-BB73-9D39C3B8D0AA}");

    var authorLinks = Globals.LinkDatabase.GetItemReferrers(authorItem, false).Where(al => al.SourceFieldID == authorFieldId).ToList();
    var categoryLinks = Globals.LinkDatabase.GetItemReferrers(categoryItem, false).Where(cl => cl.SourceFieldID == categoriesFieldId).ToList();

    var newsArticles = new List<Item>();
    foreach (var authorIl in authorLinks)
    {
        var categoryIl = categoryLinks.ToList().Find(cl => cl.SourceItemID == authorIl.SourceItemID);
        if (categoryIl != null && categoryIl.SourceDatabaseName == newsRoot.Database.Name)
        {
            newsArticles.Add(categoryIl.GetSourceItem());
        }
    }

    return newsArticles.ToArray();
}

And what do we get?   Well this.

image

It matches up pretty well the results already established. Adding the extra query seems to have added a bit to all of the query execution times – this is completely expected. In relative terms however, I think it is still very clear who the winner is.