Saying Farewell To My Baby: nemestats.com

Back in 2015 I built a website for tracking the results of board games: https://nemestats.com. If you don’t know what it is, you can learn more about it on the About page here.

In building the site I learned so much both technically and in terms of how to build and launch a (100% free, no-advertising, open-source) product from scratch. The experience really sharpened my technical skills with Microsoft Azure, .NET MVC 5, Entity Framework (EF) Code First, REST API development, Test Driven Development (TDD) Google Tag Manager, Google Analytics, SEO, and <<insert all the other buzzwords here>>. I also had the help of many awesome contributors who taught me so much along the way. Once again, see that About page for a special thanks to those who helped.

In addition to all of the learning and fun, NemeStats ended up being pretty successful. To-date, there have been nearly 10,000 Gaming Groups created and well over 300,000 games logged. Not too shabby!

Fast-forward 2019: I’ve got three young children and my career has taken an unexpected (but super-exciting!) shift away from pure software development and into Operations. I had been spending less and less time on NemeStats and I had no active contributors to the project. By 2020, I was spending almost no time on the site despite it being at its peak usage. In recent months I have been ignoring support requests entirely, which makes me feel awful. The site also costs money to keep running and there is no income source to fund it (being free with no advertising).

Given my inability to support the site any longer, I would like to offer up full ownership of NemeStats to someone (or some organization) who is willing to take care of it responsibly. If I cannot find a new owner by February 2021, I will plan to shut down the site by March 1st, 2021.

If you are interested, please contact me via email or a direct message on Twitter @jakejgordon or @nemestats.

Advertisement

UWP, .NET Standard, .NET Core, and Unit Testing (Oh My!)

tl;dr A UWP app can reference a .NET Standard 2.0 Class Library, and a .NET Core 2.1 Console Application can run unit tests against that .NET Standard Class Library.

I’m working on a UWP app and needed to write unit tests for some non-UI logic. There are a myriad of project types to pick from in Visual Studio these days, and I picked a few of the wrong types at first. It turns out that a .NET Standard 2.0 Class Library works well for housing this logic.

To test your .NET Standard 2.0 Class Library, you can create an nUnit (or xUnit or MSTest) Project (.NET Core) per the screenshot below.

net_core_unit_tests

Project Type for Testing .NET Standard 2.0 Class Library

In summary, I have a Universal Windows (UWP) app and a  nUnit Test Project (.NET Core) that both reference a .NET Standard 2.0 class library containing non-UI logic for the app to consume — and this works fine. Phew!

Entity Framework String Fields

tl;dr – Make sure you explicitly set the max length of your Entity Framework models’ string fields via the [StringLength] attribute as they are all NVARCHAR(MAX) by default, and you cannot create indexes on these fields.

When you use Entity Framework code first, all of the string fields on your models get converted toNVARCHAR(MAX) fields in the database. As of 2018, SQL Server only supports a combined index size of 900 bytes. This means that NVARCHAR(MAX) fields can never be included in an index.

You can use either the [System.ComponentModel.DataAnnotations.MaxLength] attribute or the [System.ComponentModel.DataAnnotations.StringLength] to denote the max length of a given string field. This will ensure that the backing database field is sized appropriately. The field will still need to be less than 450 characters (since NVARCHAR(450) = 900 bytes).

Here is an example of how to change a string field length so that  it is NVARCHAR(100):

[StringLength(100)]
public string Name {get; set;}

Per this stackoverflow question (and related comments), you might as well use the [StringLength] attribute as it works both for model validation and EntityFramework.

This simple addition will help keep your database sized more appropriately and will allow these additional fields to be included in SQL indexes.

Google Tag Manager and Universal Analytics

Thanks to @vfportero, we recently implemented Google Tag Manager (GTM) on nemestats.com. Our main use case for using GTM is to push events to Universal Analytics without having to write custom code on each page. Given that we have different Universal Analytics web properties per environment — one for development and one for production — we needed some way to dynamically set the Universal Analytics Tracking ID based on the environment. The goal of this article is to explain how to do this using a feature of GTM called the “data layer”.

2016-11-26 Edit: I now prefer to just use a custom javaScript variable in GTM which looks at the hostname of the request rather than having to set the Universal Analytics tracking ID on the client side. More details below in the corresponding section.

Key Google Tag Manager Concepts

First off, GTM has a few key concepts that are helpful to understand (see this article here):

  • Tags – Snippets of code that run on a page
  • Triggers – An expression that runs and evaluates to true or false
  • Variables – Are used at runtime as inputs to triggers or as values to use within GTM tags. There are a number of built-in variables that you have at your disposal within GTM (see screenshot below). You can also create your own constant variables or — and this is the cool part — you can set variables in your “data layer” on each page.

Built in GTM variables

Built in GTM variables

Prerequisites

Before we go any further let’s clarify a few things that you need to have set up. First, you need to create a Google Tag Manager account associated with your website. Second, you need to add the appropriate GTM code snippet to each page on your site. Finally, you need to have a Universal Analytics account set up and associated with your site. I’m not going to cover the details of how to set that up in this article.

Using The Data Layer

The data layer is really just a bucket of key/value pairs that make additional variables accessible within GTM. You can add variables to the data layer when the page loads or even dynamically via JavaScript. In our case, we are just going to add a variable called “universalAnalyticsTrackingId” . The value of this variable will be the Universal Analytics Tracking ID corresponding to our current environment. In .NET, we might just have an entry in our .config which we can dump out as we’ve done below. The data layer needs to be the first thing after yourtag on the page:

 <script>;
        dataLayer = [{
            <!-- '@GoogleAnalyticsConfig.GetGoogleAnalyticsTrackingId()' is just
                 a snippet of C# code that will get the tracking ID that we have
                 set in our config. Just write the appropriate code for your
                 language/framework of choice to dump out this value.-->
            'universalAnalyticsTrackingId': '@GoogleAnalyticsConfig.GetGoogleAnalyticsTrackingId()'
        }];
    </script>
<!-- Google tag manager code here-->
<!-- rest of the body-->

To see the full example, just go to any page on nemestats.com and view the page source.

Setting up a Data Layer Variable in GTM

Now that we have a data layer object populated with our Universal Analytics Tracking ID and we have our GTM snippet on the page, we can go into GTM and create a corresponding Data Layer Variable to make this variable available for use throughout GTM. Below is a step-by-step walk through of how to do this (including screenshots):

  1. Click the variables tab in GTM

    Variables tab

    Variables tab

  2. Click “New” to create a new variable
  3. Enter the name of the variable within GTM

    Create new dataLayer variable

    Create new dataLayer variable

  4. Pick the “Data Layer Variable” variable type
  5. Enter the corresponding key from the data layer of your page that this new Data Layer Variable maps to. In our case, this was “universalAnalyticsTrackingId”.

    Enter dataLayer key that this variable maps to

    Enter dataLayer key that this variable maps to

  6. Click “Create Variable”
  7. Observe that the new variable is now available within GTM

    See the new variable!

    See the new variable!

2016-11-26 Edit: The aforementioned approach may make sense for you if you have a large number of analytics properties / hostnames associated with a single deployment of your codebase. However, if you have less than a handful then there is an arguably easier way to configure your universalAnalyticsTrackingId variable to be a custom JavaScript variable like this:

function() {
if(window.location.hostname.split('.')[0] == 'nemestats') {
return 'UA-SOME-CODE-HERE';
}
return 'UA-SOME-OTHER-CODE-HERE';
}

In the above example, I’m just setting the tracking ID to my production id if the hostname is “nemestats”. Otherwise, I’m setting the tracking ID to my testing property (e.g. if the hostname is “localhost”).

Creating a Universal Analytics Event That Uses Our Data Layer Variable

Now that we have a Data Layer Variable for our Universal Analytics Tracking ID we can use it within any tags we create for Universal Analytics events. Below is another step-by-step walkthrough of how to create an event using this variable:

  1. Click the Tags tab

    Tags tab

    Tags tab

  2. Click “New” to create a new tag
  3. Enter your new tag name. This is just so you can easily identify the tag within GTM.

    Enter your tag name

    Enter your tag name

  4. Select the Google Analytics product
  5. Select the Universal Analytics Tag Type and click “Continue”

    Select Tag Type

    Select Tag Type

  6. Click on the battery birthday cake icon thing to pick an existing variable to plug in as the Tracking ID.

    Pick the data layer variable

    Pick the data layer variable

There are a number of Track Types you can select from here including Page View, Event, Social, etc. Since we’ve already demonstrated how to use the Data Layer to feed variables in GTM, we’ll leave the rest up to you for now.

Conclusion

We briefly reviewed some key Google Tag Manager concepts and then demonstrated how to set up a Data Layer and Data Layer Variable for use within GTM. In our example, we dynamically set the Universal Analytics Tracking Id in the HTML (dataLayer object) of each page on our site. We then created a GTM Variable that mapped to this dataLayer value. Last, we showed how to use this Data Layer Variable in GTM to populate the Tracking Id of a Universal Analytics tag.

Once you’ve made it this far you can use the variable throughout GTM and you should hopefully have the knowledge to create new variables that are fed from the dataLayer of your page. This opens up a plethora of possibilities for what you can track and what you can do within GTM.

REST API Design Considerations

I wrapped up development for the http://nemestats.com REST API (http://docs.nemestatsapiversion2.apiary.io/) a few months ago and I wanted to take some time to reflect upon the decisions I had to make during the process. Building a REST API from scratch can be a little daunting. This blog post is an attempt to shed some light on the key considerations that go into designing and building a REST API.

tl;dr – When designing an API consider whether you need to version it, how to version it, how to secure it, how to document it, and take care to avoid breaking changes by planning ahead.

Whether to Version Your API

Deciding whether you will always maintain backward compatibility in your API is a big decision. Supporting some kind of versioning scheme (e.g. URL, headers, query string, etc.) could significantly increase the amount of time it takes to develop your API. If you are building an API for anyone other than yourself, you will most likely need to maintain backward compatibility, and hence will need to version your API. If you are building an internal API and you can easily and simultaneously update all of the clients when you introduce a breaking change, then don’t bother versioning your API.

Since the NemeStats API is intended for third party usage, the decision to version the API was a no-brainer.

When to Version Your API

You should version your API whenever there are breaking changes to it. Here are some examples of breaking changes:

  • Removing an existing service
  • Removing a field on an object returned by an existing service
  • Changing validation rules of an existing field (e.g. a field is now required, Date must be > 1980, etc.)
  • Changing the underlying behavior of a method that is not what the original API consumer expected (e.g. a POST to /api/BoardGameBlog/ now sends an email to the entire forum when it didn’t send an email previously
  • etc, etc.

When you make breaking changes, you should provide a new, higher version of your API while allowing the old one to continue functioning — at least for a reasonable amount of time. This gives consumers the ability to upgrade at will.

How to Version Your API

Troy Hunt’s blog post on API versioning does a great job of explaining the three main approaches to versioning a REST API. This is a must-read if you are interested in the topic.

I personally prefer (and chose) to version using the URL approach because it is the most obvious and explicit to the consumer. It is also fairly easy to implement in ASP.NET Web API 2, which is my framework of choice for building REST services. Shameless plug: If you are interested in versioning a .NET REST API via the URL, check out this NuGet package and the corresponding GitHub repo which we released to assist with this challenge.

At What Level Should You Version Your API

There are at least two levels at which you could version your API. The first is at the actual service/resource level. For example, imagine you have the following service for retrieving the number of items in your shopping cart:

GET /api/v1/ShoppingCartItemsCount

Once you make a change to this service you could update just this service to have a new version by changing “v1” to “v2”:

GET /api/v2/ShoppingCartItemsCount

In this example, other services would still stay at version v1 — e.g.:

POST /api/v1/ShoppingCartItem

The problem with versioning at this level is that it requires your consumers to pay very close attention to the various resources and their versions. Furthermore, it may not be clear whether you can use version 1 of one service in conjunction with say, version 5 of another.

Versioning your entire API whenever there is a breaking change alleviates this problem. In this model, if you make a breaking change to one or more services, you release a new version of the API (e.g. /api/v2/) for all services. If you are using version 2 of the API then you know that all calls within this version are compatible.

How To Secure Your API

There are two main techniques for securing an API that I’ve used multiple times:

  • Sending an Authentication Token on Each Request – This is my preferred approach to securing APIs in most cases. Basically, you provide an authentication service like POST /UserSession that accepts a username and password and returns a unique authentication token (e.g. a GUID) if the username/password combination is valid. The client then sends this token on every request to the API as part of a header or in the query string. I prefer the use of a header like X-Auth-Token for this purpose. The API controllers then handle authentication and can return a 401 Not Authorized if the token is not legit. Note: You should always use TLS (aka SSL) when using this approach. Sniffing the credentials sent to the authentication service or even sniffing the X-Auth-Token pretty much gives the hacker full access to the API — so you really need encryption here.
  • x509 Client Certificates – You can lock down your API so that only clients with a given certificate can call the service. This is particularly useful if you are building a service that will only be called by a small set of hand-picked clients. This involves generating one (or more) certificates from a trusted root certification authority that the both the client and server trust. The API then checks that each request is signed by one of these predefined certs. Having the client install certificates — while fairly easy — may not be something you want to deal with. I would not take this approach for something like a mobile app or a public API where you could have many clients.

There are certainly other approaches like OAuth/OAuth2, Active Directory authentication, sending username and password on every request, etc. You may want to investigate these if you feel your situation warrants something different.

Plan Ahead to Avoid Breaking Your API

There some precautions you can take to reduce the chance that you’ll have to introduce breaking changes in the future. One simple design decision you can make is to ensure that your services always return an object — never just a raw string or number.

For example, imagine that you have a service that returns the number of items in the shopping cart:

GET /ShoppingCartItemsCount

You may design the service to just return a 200 OK response with the number of items in the cart like this:

2

The problem here is that if you need to add more data to the response, you don’t have an object where you can add the extra property. In this example, imagine that you also wanted to add the cost of the items in the cart. Unfortunately, since you originally returned only the number 2 instead of an object with an attribute for the number of items in the cart, you have to change the service to return something like this:


  {
    "numberOfItemsInCart" : 2,
    "totalCost" : 15.97,
    "currencyCode" : "USD"
  }

This is a breaking change. If you had started off returning an object with a “numberOfItemsInCart” attribute, then adding the additional “totalCost” and “currencyCode” fields would not be a breaking change.

How To Document Your API

The options for documenting a REST API have really matured in the last couple of years. Here are some popular options:

  • GitHub readme or GitHub wiki – Document your API in some kind of text or markdown editor from scratch (yuck!)
  • Swagger.io – Swagger is an open source framework for APIs that provides tooling to assist with visualizing your API. Swagger also has it’s own spec for building API documentation: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md
  • Apiary.io – Apiary is another framework for documenting APIs and uses a different spec called API Blueprint.
  • JSON API – JSON API is a spec that provides standards for building APIs. So far I’ve found it to be complicated but very comprehensive. If you are building an ultra-robust, gigantic, enterprise API then you might find this more appealing.

Since this space is rapidly evolving, you’ll have to do your own research to decide which one is best for you. I chose Apiary.io and have been pleased enough with the results. It’s been a little buggy, but support has been good.

Conclusion

Starting an API from scratch can be an overwhelming task. Being aware of a few important considerations can help you plan for the future. Deciding whether and how to version your API, how to secure it, how to document it, and how to avoid a few pitfalls can help you make sure your API is robust and subject to fewer breaking changes in the future.

Displaying Currency in ASP.NET

tl;dr Complete copy-and-paste C# code example at the bottom

I recently had a bad experience trying to display currency amounts in ASP.NET. Sure, displaying an amount as a currency in a given culture is simple if you assume that the amount is in the default currency type for that culture. However, this could be a really bad assumption if you are building software that serves an international market.

For example, let’s assume you have a decimal representing 1,000.00 US dollars:

decimal oneThousdandDollars = 1000.00m;

To display this amount to someone in the United States — where the US dollar is our default currency — is really quite easy:

var unitedStatesEnglishCulture = new CultureInfo("en-US");

string formattedCurrencyAmount = oneThousandDollars.ToString("C", unitedStatesEnglishCulture);

Console.WriteLine(formattedCurrencyAmount);

//output is $1,000.00

So it is in fact really easy to take a raw decimal and get a nicely formatted currency amount that looks right in the given culture. But what if we want to show 1,000 US dollars to someone in Canada, Mexico, Australia, or Columbia where they also use the same “$” local currency symbol?

An obvious example of this would be a website that sells to other marks but only transacts in one currency (e.g. US dollars). A visitor from Mexico perusing your online catalog may invoke the following code:

var mexicoSpanishCulture = new CultureInfo("es-MX");

string formattedCurrencyAmount = oneThousandDollars.ToString("C", mexicoSpanishCulture);

Console.WriteLine(formattedCurrencyAmount);

//output is $1,000.00

Do you see the problem? In Mexico the “$” means Mexican Pesos — which are worth about 1/16th the US dollar and hence the user may think the item is for sale for 1/16th of its actual price. Using the stock ASP.NET currency formatting doesn’t allow you to specify the ISO currency code of the amount. This then assumes that the amount is in the local currency of the culture you are using to display the amount.

1 USD is about 2,900 COP

1 USD is about 2,900 COP

Perhaps the simplest solution is to always use the 3-character ISO 4217 currency code instead of the local currency symbol. You probably won’t have any problems worldwide if you just display your currencies like this:

USD 1,000.00

MXN 1,000.00

GBP 1.000,00

The code for a decimal extension method for this would something like this:

public static string ToFormattedCurrencyStringWithIsoCurrencyCode(
    this decimal currencyAmount,
    string isoCurrencyCode,
    CultureInfo userCulture)
{
    string formattedNumberOnly = currencyAmount.ToString("N2", userCulture);

    //just display the 3-character ISO currency code followed by a space, followed by the numerical
    // amount formatted for the user's culture
    return string.Format("{0} {1}", isoCurrencyCode, formattedNumberOnly );
}

But let’s take the case of the average United States consumer. While most people would probably understand a “USD” prefix on an amount, we are generally much more comfortable and familiar with the dollar sign (“$”).

What if we want to beef up our extension method a bit and show the local currency symbol (e.g. $, ₽, £, etc.) when the user is viewing a currency that matches their own culture, but show the 3-digit ISO currency code when viewing a currency that is NOT local?

In other words, when an American looks at 1,000 US dollars they want to see:

$1,000.00

But when an American looks at 1,000 Columbian pesos they want to see:

COP 1,000.00

This way there is no ambiguity about whether the amount is in Columbian pesos or US dollars.

This code is a little bit more complicated, but still not too bad:

public static string ToFormattedCurrencyString(
    this decimal currencyAmount,
    string isoCurrencyCode,
    CultureInfo userCulture)
{

    //get the default ISO currency symbol for the user's culture
    //a RegionInfo requires a culture that is not neutral (i.e. it has a country associated)
    var userCurrencyCode = new RegionInfo(userCulture.Name).ISOCurrencySymbol;

    //if we are displaying a currency that matches the user's default currency,
    // then go ahead and display the currency using the local currency symbol
    if (userCurrencyCode == isoCurrencyCode)
    {
        return currencyAmount.ToString("C", userCulture);
    }

    //otherwise just display the currency with the 3-digit ISO code in front of the number
    return string.Format("{0} {1}", isoCurrencyCode, currencyAmount.ToString("N2", userCulture));

}

Voila! Now we have a pretty nice extension method for displaying currency amounts in the fashion that is best for the user. This code will take the currency code into account and won’t inadvertently change the amount into some other currency.

Technically we should add some additional protections to ensure that the isoCurrencyCode and userCulture are not null.  Since a RegionInfo requires a culture that is not neutral, we should also check this on the userCulture that is passed in. A valid culture would have a name like “en-GB” — which includes the language and country. A neutral culture would be something like “en” — which only includes the language. The code at the end of this blog entry is a little more polished with these protections in place.

This code below should display a given decimal amount in a fashion that is best for the given user’s culture.

Finished Code Example

public static string ToFormattedCurrencyString(
    this decimal currencyAmount,
    string isoCurrencyCode,
    CultureInfo userCulture)
{
    if (string.IsNullOrWhiteSpace(isoCurrencyCode))
    {
        throw new ArgumentNullException("isoCurrencyCode");
    }

    if (userCulture== null)
    {
        throw new ArgumentNullException("userCulture");
    }

    if (userCulture.IsNeutralCulture)
    {
        throw new ArgumentException(@"userCulture must not be a neutral culture. There must be a country and language so             the currency can be displayed correctly.",
        "userCulture");
    }

    var userCurrencyCode = new RegionInfo(userCulture.Name).ISOCurrencySymbol;

    if (userCurrencyCode == isoCurrencyCode)
    {
        return currencyAmount.ToString("C", userCulture);
    }
    return string.Format(
        "{0} {1}", 
        isoCurrencyCode, 
        currencyAmount.ToString("N2", userCulture));
}

Finished  Unit Tests To Go With It!

[Test]
public void It_Throws_An_ArgumentNullException_If_The_Currency_Code_Is_Null()
{
    //Arrange
    decimal SOME_DECIMAL = 1m;

    //Act
    var actualException = Assert.Throws(() =&gt; SOME_DECIMAL.ToFormattedCurrencyString(null, new CultureInfo("en-US")));

    //Assert
    Assert.That(actualException.Message, Is.EqualTo(new ArgumentNullException("isoCurrencyCode").Message));
}

[Test]
public void It_Throws_An_ArgumentNullException_If_The_Culture_Info_Is_Null()
{
    //Arrange
    decimal SOME_DECIMAL = 1m;

    //Act
    var actualException = Assert.Throws(() =&gt; SOME_DECIMAL.ToFormattedCurrencyString("USD", null));

    //Assert
    Assert.That(actualException.Message, Is.EqualTo(new ArgumentNullException("userCulture").Message));
}

[Test]
public void It_Throws_An_ArgumentException_If_The_Culture_Is_A_Neutral_One()
{
    //--Arrange
    const decimal SOME_DECIMAL = 1000.00m;
    var expectedException = new ArgumentException(
@"userCulturemust not be a neutral culture. There must be a country and language so the currency can be displayed correctly.",
"userCulture");

    //--Act
    var actualException = Assert.Throws(() =&gt; SOME_DECIMAL.ToFormattedCurrencyString("USD", new CultureInfo("en")));

    //--Assert
    Assert.That(actualException.Message, Is.EqualTo(expectedException.Message));
}

[Test]
public void It_Returns_A_Number_Formatted_For_The_Current_Users_Locale()
{
    //Arrange
    const decimal SOME_DECIMAL = 1000.00m;
    
    //Act
    string actualResult = SOME_DECIMAL.ToFormattedCurrencyString("USD", new CultureInfo("bg-BG"));

    //Assert
    Assert.That(actualResult, Is.StringContaining("1000,00"));
}

[Test]
[Ignore("You need to have the en-RU custom culture registered for this test to pass.")]
public void It_Returns_A_Number_Formatted_For_The_Current_Users_Locale_Even_If_The_Culture_Is_A_Custom_One()
{
    //Arrange
    const decimal SOME_DECIMAL = 1000.00m;

    //Act
    string actualResult = SOME_DECIMAL.ToFormattedCurrencyString("RUB", new CultureInfo("en-RU"));

    //Assert
    Assert.That(actualResult, Is.StringStarting("₽"));
}

[Test]
public void It_Returns_The_Local_Currency_Symbol_If_The_Users_Cultures_Currency_Matches_The_Passed_In_Currency_Code()
{
    //Arrange
    const decimal SOME_DECIMAL = 1000.00m;

    //Act
    string actualResult = SOME_DECIMAL.ToFormattedCurrencyString("GBP", new CultureInfo("en-GB"));

    //Assert
    Assert.That(actualResult, Is.StringStarting("£"));
}

[Test]
public void It_Returns_The_ISO_Currency_Code_If_The_Users_Cultures_Currency_Does_Not_Match_The_Passed_In_Currency_Code()
{
    //Arrange
    const decimal SOME_DECIMAL = 1000.00m;

    //Act
    string actualResult = SOME_DECIMAL.ToFormattedCurrencyString("GBP", new CultureInfo("en-US"));

    //Assert
    Assert.That(actualResult, Is.StringStarting("GBP"));
}

I hope this article helps explain the pitfalls of default currency handling in ASP.NET and provides you with some useful code to work around these more complex scenarios.

Eager Loading Of Related Entities in LLBLGen Pro

In a recent blog post we took a look at how Entity Framework (version 6) handles eager loading and lazy loading of entities (or POCOs as the examples were using Code First). In this post we’ll take a look at another .NET ORM tool — LLBLGen Pro — to see how it handles eager loading of entities (or “prefetching” as it’s called with LLBLGen Pro). All of the integration tests backing these observations are openly available to check out on GitHub and are decently commented if you’d rather just let the code do the talking.

The specific goals of this post are to:

  • Overview the basics of prefetching in LLBLGen Pro using the LINQ to LLBLGen Pro in conjunction with the Adapter template group
  • Demonstrate the actual SQL queries that LLBLGen Pro emits in various prefetching scenarios
  • Understand how and what relations are populated in these scenarios
  • Take a closer look at how projections behave in terms of the above

Before we dive in, there are a few things worth mentioning about LLBLGen Pro and how it differs from the previous Entity Framework examples:

  • LLBLGen Pro has multiple query systems available and my examples are using the LINQ to LLBLGen Pro method. You’ll also see the use of some LLBLGen Pro extension methods which let you do things like prefetch and filter related entities, etc.
  • The method I’ve chosen does not support lazy loading of entities, although LLBLGen Pro does appear to support this if you use the “Self Servicing” method of querying.
  • LLBLGen Pro uses entity classes which it generates to represent constructs in the database. These entities are not POCOs like the models I used in the Entity Framework examples.

I’ll do another blog post sometime soon to do a more strict apples to apples comparison of Entity Framework vs. LLBLGen Pro over some specific examples. My intention is not to compare the two here, but merely demonstrate how LLBLGen Pro behaves.

I used the exact same database that I used for the Entity Framework examples, but here are there three tables again for reference:

Person
Id – int – PK
Name – nvarchar

Pet
Id – int – PK
Name – nvarchar
OwningPersonId – int – FK to Person.Id
FavoritePetFoodBrandId – int – FK to PetFoodBrand.Id

PetFoodBrand
Id – int – PK
Name – nvarchar

Basic Example With No Prefetching

Here is how you could retrieve a single person — Jane — via LINQ to LLBLGen Pro using the Adapter template group:

using (DataAccessAdapter adapter = new DataAccessAdapter())
{
    LinqMetaData metaData = new LinqMetaData(adapter);

    PersonEntity person = (from p in metaData.Person
        where p.Name == "Jane"
        select p).First();
}

As you would probably expect, this will retrieve a Person with an empty (as opposed to null) Pets collection, since Pets weren’t prefetched.

And here is the SQL query that was generated behind the scenes:

SELECT TOP(@p2) [LPA_L1].[Id], [LPA_L1].[Name] 
FROM [Examples.ExampleDbContext].[dbo].[Person]  [LPA_L1]   
WHERE ( ( ( [LPA_L1].[Name] = @p3)))

Parameter: @p2 : Value: 1
Parameter: @p3 : Value: "Jane"

Example of Prefetching One Relationship

Here is an excerpt from an integration test showing how to retrieve Jane with all of her Pets populated:

PersonEntity result = 
   (from person in metaData.Person.WithPath(a => a.Prefetch(b => b.Pets))
    where person.Name == "Jane"
    //select person with Pets which is prefetched
    select person).First();

Assert.That(result.Name, Is.EqualTo("Jane"));
//the Pets collection is actually populated here
Assert.That(result.Pets, Is.Not.Empty);

The SQL that is generated here is a little more interesting. You’ll notice that LLBLGen Pro generated two queries — one for each table.

//select the Person
SELECT TOP(@p2) [LPA_L1].[Id], [LPA_L1].[Name] FROM [Examples.ExampleDbContext].[dbo].[Person]  [LPA_L1]   WHERE ( ( ( [LPA_L1].[Name] = @p3)))

Parameter: @p2 : Value: 1
Parameter: @p3 : Value: "Jane"

//select all pets for that Person
SELECT [Examples.ExampleDbContext].[dbo].[Pet].[FavoritePetFoodBrandId], [Examples.ExampleDbContext].[dbo].[Pet].[Id], [Examples.ExampleDbContext].[dbo].[Pet].[Name], [Examples.ExampleDbContext].[dbo].[Pet].[OwningPersonId] FROM [Examples.ExampleDbContext].[dbo].[Pet]   WHERE ( ( ( [Examples.ExampleDbContext].[dbo].[Pet].[OwningPersonId] = @p1)))

Parameter: @p1 : Value: 1.

These queries happen behind the scenes and the resulting Person object will automatically have the Pets relationship populated.

Example of a Prefetching Multiple Levels Deep

Notice in the below query we do a .SubPath to go more than one level deep:

PersonEntity result = 
    (from person in metaData.Person
    .WithPath(a => a.Prefetch(b => b.Pets)
        .SubPath(c => c.Prefetch(d => d.PetFoodBrand)))
    where person.Name == "Jane"
    select person).First();

Assert.IsNotEmpty(result.Pets);
Assert.That(result.Pets[0].PetFoodBrand, Is.Not.Null);

Notice that this generates three queries: one for Person, one for Pets, and one for PetFoodBrands.

//first query for the Person
SELECT TOP(@p2) [LPA_L1].[Id], [LPA_L1].[Name] FROM [Examples.ExampleDbContext].[dbo].[Person]  [LPA_L1]   WHERE ( ( ( [LPA_L1].[Name] = @p3)))

Parameter: @p2 : Value: 1
Parameter: @p3 : Value: "Jane"

//then query for all Pet records that have this person as the owner
SELECT [Examples.ExampleDbContext].[dbo].[Pet].[FavoritePetFoodBrandId], [Examples.ExampleDbContext].[dbo].[Pet].[Id], [Examples.ExampleDbContext].[dbo].[Pet].[Name], [Examples.ExampleDbContext].[dbo].[Pet].[OwningPersonId] FROM [Examples.ExampleDbContext].[dbo].[Pet]   WHERE ( ( ( [Examples.ExampleDbContext].[dbo].[Pet].[OwningPersonId] = @p1)))

Parameter: @p1 : Value: 1

//then query for every PetFoodBrand for all pets that were retrieved in the previous query
SELECT [Examples.ExampleDbContext].[dbo].[PetFoodBrand].[BrandName], [Examples.ExampleDbContext].[dbo].[PetFoodBrand].[Id] FROM [Examples.ExampleDbContext].[dbo].[PetFoodBrand]   WHERE ( [Examples.ExampleDbContext].[dbo].[PetFoodBrand].[Id] IN (@p1, @p2))

Parameter: @p1 : Value: 1
Parameter: @p2 : Value: 2

This query-per-table approach is actually quite scalable compared to the always-join approach which is prone to generating inefficient and bloated result sets.

Example of Prefetch With Filter On Related Entity

Using LLBLGen Pro you can also filter out related entities from being populated. Below is another integration test excerpt:

PersonEntity result = (from person in metaData.Person
    .WithPath(a => a.Prefetch(b => b.Pets)
      //prefetch PetEntities but only retrieve Fluffy
      .FilterOn(c => c.Name == "Fluffy"))
    where person.Name == PERSON_JANE
    //select person with Pets which is explicitly prefetched
    select person).First();

//only one result is retrieved
Assert.That(result.Pets.Count, Is.EqualTo(1));
//...and that result is Fluffy!
Assert.That(result.Pets[0].Name, Is.EqualTo("Fluffy"));

Below are the queries that were generated:

SELECT TOP(@p2) [LPA_L1].[Id], [LPA_L1].[Name] FROM [Examples.ExampleDbContext].[dbo].[Person]  [LPA_L1]   WHERE ( ( ( [LPA_L1].[Name] = @p3)))

Parameter: @p2 : Value: 1
Parameter: @p3 : Value: "Jane"

SELECT [Examples.ExampleDbContext].[dbo].[Pet].[FavoritePetFoodBrandId], [Examples.ExampleDbContext].[dbo].[Pet].[Id], [Examples.ExampleDbContext].[dbo].[Pet].[Name], [Examples.ExampleDbContext].[dbo].[Pet].[OwningPersonId] FROM [Examples.ExampleDbContext].[dbo].[Pet]   WHERE ( ( ( [Examples.ExampleDbContext].[dbo].[Pet].[OwningPersonId] = @p1))
//notice that the .FilterOn criteria is applied here
AND ( [Examples.ExampleDbContext].[dbo].[Pet].[Name] = @p2))

Parameter: @p1 : Value: 1
Parameter: @p2 : Value: "Fluffy"

 Example of a Simple LINQ Projection

You can of course build projections if you want to cherry pick specific fields or relationships. Here is the simplest example:

String personName = (from p in metaData.Person
    where p.Name == PERSON_JANE
    select p.Name).First();

Here is the SQL that was generated. Notice it only selects the Name column rather than fetching the entire row.

SELECT TOP(@p2) [LPLA_1].[Name] FROM [Examples.ExampleDbContext].[dbo].[Person]  [LPLA_1]   WHERE ( ( ( ( ( ( [LPLA_1].[Name] = @p3))))))

Parameter: @p2 : Value: 1
Parameter: @p3 : Value: "Jane"

 Example of a LINQ Projection Pulling Back Relationships

You can also pull back multiple types of entities using a projection. Here is another integration test excerpt:

var result = (from person in metaData.Person
    where person.Name == PERSON_JANE
    //select Pets, even though it wasn't explicitly prefetched
    select new
    {
        Person = person,
        Pets = person.Pets
    }).First();

Assert.That(result.Person, Is.Not.Null);
Assert.That(result.Pets, Is.Not.Empty);
//The Pets relationship on Person is not populated!
Assert.That(result.Person.Pets, Is.Empty);

Something important to call out here is that when using projections to pull from various tables ad-hoc and without prefetching means that the relationships on the retrieved entities will not be populated.

Here is the generated SQL:

SELECT TOP(@p4) [LPLA_1].[Id], [LPLA_1].[Name], @p2 AS [LPFA_3], 1 AS [LPFA_4] FROM [Examples.ExampleDbContext].[dbo].[Person]  [LPLA_1]   WHERE ( ( ( ( ( ( [LPLA_1].[Name] = @p5))))))

Parameter: @p2 : Value: 1
Parameter: @p4 : Value: 1
Parameter: @p5 : Value: "Jane"

SELECT [LPA_L1].[FavoritePetFoodBrandId], [LPA_L1].[Id], [LPA_L1].[Name], [LPA_L1].[OwningPersonId] FROM [Examples.ExampleDbContext].[dbo].[Pet]  [LPA_L1]   WHERE ( ( [LPA_L1].[OwningPersonId] = @p1))

Parameter: @p1 Value: 1

Example Of A Query With More Than 50 Entities In Related Table

LLBLGen Pro also has automatic tuning of queries where subsequent queries with more than 50 predicates will be consolidated into a single query with a subselect as performance can start to degrade once there are a large number of predicates. This limit is configurable at run time. Here is yet another integration test excerpt, only this time it pulls back all Persons. Trust me that there are > 50 persons in the database.

var result = (from person in metaData.Person
    .WithPath(a => a.Prefetch(b => b.Pets))
    //select person with Pets
    select person).ToList();

And now notice that there is a single query that uses a subselect:

SELECT [Examples.ExampleDbContext].[dbo].[Pet].[FavoritePetFoodBrandId], 
[Examples.ExampleDbContext].[dbo].[Pet].[Id], 
[Examples.ExampleDbContext].[dbo].[Pet].[Name], 
[Examples.ExampleDbContext].[dbo].[Pet].[OwningPersonId] 
FROM [Examples.ExampleDbContext].[dbo].[Pet]   
WHERE ( [Examples.ExampleDbContext].[dbo].[Pet].[OwningPersonId] IN 
(SELECT [LPA_L1].[Id] FROM [Examples.ExampleDbContext].[dbo].[Person]  [LPA_L1]  ))

Wrapping Things Up

We’ve taken a look at how LLBLGen Pro handles eagerly loading relationships and have covered some of the most common scenarios. I’ll try to have a follow up post to do an apples to apples comparison of Entity Framework 6 and LLBL 4 to discuss the differences in how they generate the underlying SQL queries and how resulting entities/POCOs are presented. Stay tuned.

Try Not To Reference Your DbContext In Entity Framework Code First Migrations

I recently ran into a problem where a developer was trying to pull down the latest version of the NemeStats codebase (https://github.com/jakejgordon/NemeStats) was getting the below error when running the Entity Framework code first migrations via “update-database”. The error was:

The model backing the ‘NemeStatsDbContext’ context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).

The most common proposed solution to this error is to add the following line to your Global.asax.cs Application_Start():

Database.SetInitializer<MyContext>(null);

However, in my case I was getting the error because I had a migration that actually referenced my DbContext directly rather than using the Sql method that is available in Entity Framework migrations. The problem with this is that the developer was starting with a fresh database that was on say, version 1 but the most current version of the code corresponded to say, version 15 of the database. When the offending migration runs and references the DbContext directly it is assuming the DbContext has models that were in place when the migration was written. When a developer runs “update-database” with the current version of the models and custom code runs, the models could be wildly out of sync with the code that was in the migration and the above error is thrown. Let’s take a look at the following example to illustrate the problem.

Migration 1

A new Player table is created with an Id and Name column:

public override void Up()
{
    CreateTable(dbo.Player", c => new
    {
        Id = c.Int(nullable: false, identity: true),
        Name = c.String(),
    }).PrimaryKey(t => t.Id);
}

Migration 2

This migration uses the DbContext directly to update the Player table, rather than using Sql(…). This will work fine so long as the models associated with ExampleDbContext never change from this point forward. Not likely!

public override void Up()
        {
            using (ExampleDbContext dbContext = new ExampleDbContext())
            {
                Player playerToUpdate = (from player in dbContext.Players
                                 where player.Name == "Foo"
                                 select player).FirstOrDefault();

                if (playerToUpdate != null)
                {
                    playerToUpdate.Name = "Bar";
                    dbContext.SaveChanges();  
                }
            }
        }

Migration 3

This migration makes a change to the Player model/table by adding another column called DateRegistered. This migration is listed just to demonstrate that the Player model backing the ExampleDbContext will have an extra property in the most current version of the code.

public override void Up()
{
    AddColumn("dbo.Player", "DateRegistered", c => c.DateTime());
}

What Happens When You Run These Migrations With a Fresh Database

The first migration will run just fine and will create the Player table.

The second migration will fail and give the error:

The model backing the ‘ExampleDbContext’ context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).

The problem is that the current version of the code has a Player model with Id, Name, and DateRegistered. When you first access the ExampleDbContext in Migration 2, the database doesn’t yet have the DateRegistered column (since this is added in Migration 3 which hasn’t run yet). Entity Framework compares the models with the database and realizes that they are not in sync, and throws this error.

Conclusion and How To Avoid This Problem

The short answer is that you should really try to avoid referencing your DbContext directly in a migration as it will eventually cause problems when your model changes.  Whenever you have to pull down the project with a fresh database your migrations will fail when you run update-database. If you need to access or manipulate the database you should use the built-in methods that are on the DbMigration class which all migrations extend. In the example above, rather than updating the player using the DbContext, I should have updated it using the Sql method in my migration as follows:

Sql(“UPDATE Player Set Name = ‘Bar’ WHERE Name = ‘Foo’;”);

There may actually be times when you have a good reason to want to run code and reference your DbContext in a migration, but this is a topic for another post.

Hopefully this helps someone else who runs into this problem!

Entity Framework Eager vs. Lazy Loading

I recently ran into an issue on NemeStats.com where an Entity Framework 6 LINQ query wasn’t fetching some related entities even though I had explicitly included them (via .Include(“EntityName”). As a result, I created a simple integration test project to demonstrate a number of basic Entity Framework common scenarios and the SQL that is emitted from these queries. My goals were as follows:

  1. Troubleshoot why in some cases related entities were being fetched properly and in other cases they were not. In particular, why is there a difference when selecting an entity as a property on an anonymous object vs. selecting the entity directly?
  2. Confirm my understanding of Lazy vs. Eager loading in Entity Framework. This ended up being related to #1
  3. Understand exactly when it is necessary to .Include() entities and when it is not.
  4. See what the actual SQL looks like that Entity Framework generates for some really commons scenarios.

The code is available on GitHub at: https://github.com/jakejgordon/Entity-Framework-Integration-Tests-and-Examples/blob/master/EF6Examples/Examples/Tests/LazyLoadingExamples.cs and is probably worth skimming through as I’ve commented each of the scenarios to show the SQL that was emitted.

For a little more context, I created a new database with the following three tables:

Person
Id – int – PK
Name – nvarchar

Pet
Id – int – PK
Name – nvarchar
OwningPersonId – int – FK to Person.Id
FavoritePetFoodBrandId – int – FK to PetFoodBrand.Id

PetFoodBrand
Id – int – PK
Name – nvarchar

Conclusion and Takeaways

If you don’t want to bother checking out the code and coming to your own conclusions, here are the things I learned in this experiment:

  • Lazy loading is on by default and can cover up some bad things if you aren’t careful. For example, pulling back a Person entity and then iterating over a list of Person.Pets will do a separate query for each Pet if you didn’t explicitly .Include(“Pet”). In many cases this is OK, but in many cases this could results in hundreds or thousands of additional queries that you may not have been expecting. Personally I prefer to turn off lazy loading so I don’t accidentally let one of these scenarios happen. I don’t see many cases in a web application where you would actually want to lazy load.
  • If you only need a single field from a table then use the LINQ query syntax to pull just that one field rather than loading the entire entity. For example, if you just want to fetch the Name of a Person you can do:


    string name = (from person in dbContext.Persons
    where person.Name == "Jane"
    select person.Name).First();

  • If you use the LINQ query syntax (i.e. from … where … select) and select an anonymous object then the included entities are NOT eagerly fetched on the projection… unless you fetch those relationships explicitly in the projection.

    This example will have Pets eagerly loaded:


    Person person = dbContext.Persons
    .Include("Pets")
    .First(p => p.Name == "Jane");

    This example will not have Pets eagerly loaded:


    Person person = (from person in dbContext.Persons
    .Include("Pets")
    where person.Name == "Jane"
    select new
    {
    Person = person
    }).First();

    This example will have Pets and FavoriteFoodBrands eagerly loaded because Pets and FavoriteFoodBrands are explicitly fetched in the project and will be populated into their according relationships of the current DbContext instance:


    var result = (from person in dbContext.Persons
    where person.Name == PERSON_JANE
    select new
    {
    Person = person,
    Pets = person.Pets,
    FavoriteFoodBrands = person.Pets.Select(p => p.FavoritePetFoodBrand)
    }).First();

    In other words, all of the below Asserts pass:
    Assert.That(result.Person, Is.Not.Null);
    Assert.That(result.Person.Pets, Is.Not.Null);
    Assert.That(result.Pets, Is.Not.Null);
    Assert.That(result.FavoriteFoodBrands, Is.Not.Null);
    Assert.That(result.Person.Pets.Select(pet => pet.FavoritePetFoodBrand).Count(), Is.GreaterThan(0));

  • Attempting to fetch an entity that was already fetched on a given DbContext instance will not bother going back to the database since it is already cached up on the DbContext. In my particular case, I didn’t notice a bug in my application because I happened to be fetching all of these entities on a different query earlier in the call stack. When I went to .Include(“MyRelatedEntity”) on a new query this didn’t actually do anything because I was selecting an anonymous object (see previous bullet) — but it happened to work anyway because all of MyRelatedEntity objects were already cached up on my DbContext. I only discovered the bug later when I attempted to include an entity that wasn’t already cached up and the result was always null.
  • It is only necessary to use .Include (e.g. .Include(“Pets”)) when you are fetching an entity and want that relationship to be pre-populated when you pull the entity back (e.g. you “select person” and want person.Pets to be populated). It is a common misconception that you need to Include related entities if you are selecting them explicitly or as part of an anonymous object. For example, if you want to eagerly (in one query) retrieve Jane and all of her Pets, use the .Include like this:


    Person person = dbContext.Persons
    .Include("Pets")
    .First(p => p.Name == "Jane");

    However, if you just want to retrieve Jane’s name and her pets’ names, you can just do this:


    var result = (from person in dbContext.Persons
    where person.Name == PERSON_JANE
    select new
    {
    PersonName = person.Name,
    PetNames = person.Pets.Select(pet => pet.Name)
    }).First();

    This comes especially in handy when you have tables with a large number of columns and only need to retrieve a small set of those columns. The SQL generated here will only select the needed columns.

Idiomatic C# and the “I” Prefix

In a prior blog post (https://jakejgordon.wordpress.com/2014/08/24/to-blog-or-to-code/) I mentioned a for-fun side project I’ve been working on. I also mentioned that I’d share some lessons learned in a subsequent blog posts… so here we are!

I planned on rolling up a number of lessons learned in one post but realized it would be too long. Plus I like Bertrand Le Roy’s idea of applying the Single Responsibility Principle to blog posts so let’s hone in on one specific topic:

Using the “I” Prefix for Interface Names in .NET

In “Clean Code” by Uncle Bob Martin, he recommends not using the “I” prefix for interface names. He contends that if you cannot come up with a descriptive enough implementation name then an “Impl” (for implementation) suffix is still better than an “I” prefix (i.e. ThingDoerImpl is better than IThingDoer). While the book is written primarily from a Java perspective, I thought I’d try it out on a .NET project knowing that this was very much contrary to a long-standing C# convention. After about 5 months of developing without the “I” prefix, below are my takeaways on the good and the bad.

Reasons to Drop The “I” Prefix

Better Implementation Names – Not having the “I” prefix helped force me to come up with better names for my implementations. For example, instead of just having IThingDoer (interface) and ThingDoer (implementation), I would instead try to go with something like ThingDoer (interface) and ThingDoerThatDoesItACertainWay (implementation). If I was really not feeling inspired I would default to ThingDoer and ThingDoerImpl (implementation). While this isn’t great, it at least allowed me to not to have to add the “I” prefix.

Related Files Grouped Together – With the “I” prefix, your interface and implementation are usually not grouped together in Visual Studio’s Solution Explorer. In your IDE you end up with something like the below (alphabetical ordering):
AppleSlicer
BananaSmasher
GraperSquisher
IAppleSlicer
IBananaSmasher
IGrapeSquisher
ILemonSqueezer
LemonSqueezer

At least if you don’t have the “I” prefix you’ll have the slightly more convenient:
AppleSlicer
AppleSlicerImpl
BananaSmasher
BananaSmasherImpl
GrapeSquisher
GrapheSquisherImpl
LemonSqueezer
LemonSqueezerImpl

Reasons To Use the “I” Prefix

Visual Studio Solution Explorer Doesn’t Distinguish Between Classes and Interfaces by Default – While the Class View in Visual Studio clearly calls out interfaces vs. implementations, the Solution Explorer does not — presumably because you can have both classes and implementations in a single .cs file (although I prefer to never do this). This means that a clear naming convention (i.e. the “I” prefix) is the only easy way to tell if a file represents a class or an interface.

Unable To Distinguish Between Implementing Interface and Extending a Base Class – In C# the colon (“:”) is used to denote both implementing interfaces as well as extending base classes. In Java you have the “extends” and “implements” keywords to help distinguish between classes as interfaces when you are defining your inheritence. For example, in java you could have:

public class SomeClass extends SomeBaseClass implements SomeInterface

In C# you would just have:
public class SomeClass : SomeBaseClass, SomeInterface

Without a clear naming convention to call out the base class vs. the interface you might not be able to easily tell which is which. Take for example:public class SomeClass : LemonSlicer, ApplePeeler

Are these interfaces or classes? Or is LemonSlicer a base class and ApplePeeler is an interface?

Long Standing Convention – As much as I don’t like to give this as a reason, one cannot overlook the fact that the “I” prefix is a convention that all C# developers understand and expect. While I was getting pretty comfortable without the “I” prefix in my own code (with which I was obviously very familiar), other developers were confused and frustrated when trying to work with the code. Given that I’d actually like other people to help me with my project this is pretty much the deal-breaker.

Conclusion

Dropping the “I” prefix wasn’t nearly as painful as I thought it would be. It forced me to pick better names for my implementations and I found the grouping of files to be more convenient in the Visual Studio Solution Explorer. However, the simple fact that developers expect the “I” prefix is probably a good enough reason to keep with the status quo — which I’ll be doing from here on out.

What do you think?