Deleting a Remote Git Branch

Since I have to look this up *every* *single* *time*, I’ll just leave this post here for my own benefit (and hopefully others’).

Here are the git commands that one would use to delete both local and remote branches:

$ git push --delete <remote_name> <branch_name>
$ git branch -d <branch_name>

Additional detailed information about this can be found at the Stack Overflow post that I have found myself looking up over and over.

 

T-SQL: Sorting Numeric Values That Are Stored As Strings

Following are some tricks that I have found useful for sorting numeric data that is stored as strings. Normally, string values of "2", "1", and "11" will sort as "1", "11", "2". The examples below will sort this sequence as "1", "2", "11" instead.

One caveat; I have not performed extensive performance testing or examined query plans to get an idea of the efficiency of these queries. Be sure to perform your own evaluations before using these in production environments.

For the first example, set up a sample table and some relatively clean test data. The data is "clean" because it is uncomplicated by leading zeros or spaces. For our sample table, there are two columns with numeric data stored as strings: Volume and Series.

CREATE TABLE #Book
(
BookID int identity(1,1) NOT NULL PRIMARY KEY,
Title nvarchar(200) NOT NULL DEFAULT(”),
Volume nvarchar(20) NOT NULL DEFAULT(”),
Series nvarchar(20) NOT NULL DEFAULT(”)
)

INSERT #Book (Title, Volume, Series) VALUES (‘Journal of Sloths’, ’13’, ”)
INSERT #Book (Title, Volume, Series) VALUES (‘Journal of Sloths’, ‘1’, ‘3’)
INSERT #Book (Title, Volume, Series) VALUES (‘Journal of Sloths’, ‘1’, ‘new’)
INSERT #Book (Title, Volume, Series) VALUES (‘Journal of Sloths’, ‘5’, ”)
INSERT #Book (Title, Volume, Series) VALUES (‘Journal of Sloths’, ‘1’, ‘1’)
INSERT #Book (Title, Volume, Series) VALUES (‘Journal of Sloths’, ‘4’, ”)

If you know that you have clean data such as this, this simple query will sort the string values in the Volume and Series columns as numerics.

SELECT        *
FROM        #Book
ORDER BY
        Title,
        RIGHT(SPACE(20) + Volume, 20),
        RIGHT(SPACE(20) + Series, 20)

As you can see, this was achieved by padding each column with its maximum length (20 characters) in spaces, and then sorting by the rightmost 20 characters of each value. Here are the results:

BookID   Title                    Volume   Series
5        Journal of Sloths        1        1
2        Journal of Sloths        1        3
3        Journal of Sloths        1        new
6        Journal of Sloths        4       
4        Journal of Sloths        5       
1        Journal of Sloths        13

For the next example, add some ‘dirty’ data to the Volume column. This new data is numeric values with leading zeros.

INSERT #Book (Title, Volume, Series) VALUES (‘Journal of Sloths’, ‘012’, ”)
INSERT #Book (Title, Volume, Series) VALUES (‘Journal of Sloths’, ’02’, ”)

The following query builds on the first example and handles the dirty data by removing the leading zeros. This is accomplished by converting the values to numeric and then back to nvarchar during the sort operation, like so:

SELECT        *
FROM        #Book
ORDER BY
Title,
        RIGHT(SPACE(20) + CONVERT(nvarchar(20), CONVERT(int, Volume)), 20),
        RIGHT(SPACE(20) + Series, 20)

The results:

BookID   Title                    Volume   Series
5        Journal of Sloths        1        1
2        Journal of Sloths        1        3
3        Journal of Sloths        1        new
8        Journal of Sloths        02       
6        Journal of Sloths        4       
4        Journal of Sloths        5       
7        Journal of Sloths        012       
1        Journal of Sloths        13       

Now add some ‘dirty’ data to the Series column.

INSERT #Book (Title, Volume, Series) VALUES (‘Journal of Sloths’, ‘1’, ’02’)

The prevoius method of converting the Series column to a numeric value and then back to nvarchar is shown here.

SELECT        *
FROM        #Book
ORDER BY
        Title,
        RIGHT(SPACE(20) + CONVERT(nvarchar(20), CONVERT(int, Volume)), 20),
        RIGHT(SPACE(20) + CONVERT(nvarchar(20), CONVERT(int, Series)), 20)

However, in this case, the result is the following error: "Conversion failed when converting the nvarchar value ‘new’ to data type int." This happens because the Series column includes a value of "new" in addition to all of the numeric values. The value "new" cannot be converted to a numeric, so the result is an error.

The solution is to add CASE statements to the ORDER BY clause so that conversions to numeric are only performed if the values are actually numeric. The value is not numeric it is sorted as-is. Here is the final query.

SELECT        *
FROM        #Book
ORDER BY
        Title,
        RIGHT(SPACE(20) +
                CASE WHEN ISNUMERIC(Volume) = 1 THEN CONVERT(nvarchar(20),
                CONVERT(int, Volume)) ELSE Volume END, 20),
        RIGHT(SPACE(20) +
                CASE WHEN ISNUMERIC(Series) = 1 THEN CONVERT(nvarchar(20),
                CONVERT(int, Series)) ELSE Series END, 20)

And the final set of results:

BookID   Title                    Volume   Series
5        Journal of Sloths        1        1
9        Journal of Sloths        1        02
2        Journal of Sloths        1        3
3        Journal of Sloths        1        new
8        Journal of Sloths        02       
6        Journal of Sloths        4       
4        Journal of Sloths        5       
7        Journal of Sloths        012       
1        Journal of Sloths        13       

Obviously, the more logic that is added to the ORDER BY clause, the more performance will be affected. Choose the simplest query that satisfies the requirements imposed by your data, and always remember to evaluate the performance under real-world conditions.

Dev Up Conference 2017 – Session Resources

This week I attended the Dev Up Conference in St. Louis.  I thought that the (new) venue, food, and speakers were all excellent, and improved upon past editions of the conference.  Kudos to all involved; they must have put in a lot of hard work.

As usual after attending a conference such as this, I attempt to accumulate links to as many of the session resources as I can find (on twitter, youtube, blogs, and so on), and share them here on my blog.  I do this because I figure that I am not the only one that had to skip great sessions because they were scheduled at the same time as other equally great sessions.

So without further ado, here is the list of all session from this year’s Dev Up Conference, with as many links to additional information as I could find.  Apologies for any that I missed.

Also, a number of the sessions were recorded.  I assume that they will be posted online by the Dev Up organizers, so keep an eye on the conference web site for those.

.CSS {Display: What?}
Martine Dowden

.NET and Couchbase: Using NoSQL Is Easier Than You Think
Don Schenck

.NET, Linux and Microservices Architecture
Don Schenck

1 Billion Records IS NOT BIG DATA PEOPLE!
Steve Howard

5 Popular Choices for NoSQL on a Microsoft Platform
Matthew Groves

A Brisk Stroll Through AzureML Studio
Kevin Queen

A feature based approach to software development
Ryan Lanciaux

A Guide to JavaScript’s Scary Side
Jonathan Mills

A Lap Around Xamarin.Forms
Douglas Starnes

A Skeptics Guide to Functional Style JavaScript
Jonathan Mills

Accessibility Cookbook: 10 Easy Recipes
Martine Dowden

Adding Realtime Features to Your Applications with SignalR
Javier Lozano

Agile Delivery in a Waterfall World
John Gobble

Agile Failures: Stories From The Trenches
Philip Japikse

Agile Metrics That Matter
Clint Edmonson

Agile: You Keep Using That Word…
Philip Japikse

All The New Things: A Madcap Tour of the latest in Microsoft Web Development
Brad Tutterow

An Entrepreneur’s Tale
Randy Walker

An Extended Explanation of Caching
Tom Cudd

An Introduction to Microservices
Mike Green

Angular vs. React: A live demonstration, comparison, and discussion
Kevin Grossnicklaus

Angular, the ASP.NET Pitch
Ed Charbeneau

ASP.NET Core + React Equals Awesome
Lee Brandt

Authentication and Security Strategies for the Modern Web
Spencer Schneidenbach

Azure SQL Data Warehouse, Cloud BI
Randy Walker

Becoming an Architect
Ken Sipe

Beginner Reactive Programming with RxJS
Cory Rylan

Between Two Form Tags
Danielle Cooley

Build a JavaScript Dev Environment in 1 Hour
Cory House

Building a Chat Bot with API.ai
Erin Page

Building A Highly Scalable Service that Survived A Super Bowl
Keith Elder

Building Powerful Applications with Angular and TypeScript
David Giard

Building Reusable UI Components in ASP.NET Core MVC
Scott Addie

Building Your Evil(?) Empire with Azure Functions
Bryan Soltis

Bus Accident Management
James West

Career Management – Better than Career Development
John Maglione

Career Paths Beyond Sr. Developer
Jim Drewes

Cloud Networking: What’s Underneath?
James Nugent

Code Is Communication
Steven Hicks

Compromise Less and Deliver More with Xamarin
David Ortinau

Confronting Your Fears: Entity Framework Performance Deep-dive
Mitchel Sellers

Continuous Delivery at Enterprise Scale
Jason Whittington

Custom Middleware & Microservices with ASP.NET Core
Ondrej Balas

Data Science Platform Architecture
Ryan Metcalf

Database DevOps in Visual Studio 2017 Enterprise with ReadyRoll Core
Ronnie Hicks

Dockerize Your Development
Lee Brandt

Domain Driven Design: The Good Parts
Jimmy Bogard

Effective Data Visualization
David Giard

Electron: Desktop Development for Web Developers
Chris Woodruff

Everything I Didn’t Know About JavaScript
Brad Tutterow

Fear and (Self) Loathing in IT – A Healthy Discussion on Imposter Syndrome
Angela Dugan

Feed Your Inner Data Scientist: JavaScript Tools for Data Visualization and Filtering
Doug Mair

Forget Velocity, Let’s Talk Acceleration
Jessica Kerr

From C# 6 to C# 7, Then and Now!
David Pine

From Developer to Data Scientist
Gaines Kergosien

Getting Started with Machine Learning, for Non-Data Scientists
Yung Chou

Git Demystified
Kent Peek

Giving Clarity to LINQ Queries by Extending Expressions
Ed Charbeneau

Growing a Dev Team from Bootstrap to Enterprise
Scott Connerly

Have Your Best Season Yet: Becoming a (Microsoft) MVP
Lisa Anderson

HoloLens Mixed Reality for Fun & Profit
Gaines Kergosien

How do You Measure up? Collect the Right Metrics for the Right Reasons
Angela Dugan

How Mobile Web Works at Twitch
Matt Follett

I, for One, Welcome Our Robot Overlords: Intro to the Bot Framework
John Alexander

Implementing a Modern Web Stack in a Legacy Environment
James West

Implementing Web Security in Your ASP.NET Applications
Javier Lozano

Intellectual Property Fundamentals for the Technologist
Jeff Strauss

Intro to Hacking with the Raspberry Pi
Sarah Withee

Intro to Xamarin
Ryan Overton

Introduction to Amazon AWS
Brian Korzynski

Introduction to Angular
Muljadi Budiman

Introduction to Asynchronous Code in .NET
Bill Dinger

Introduction to Online Security
Michael Dowden

Introduction to the D3.js visualization library
Bryan Nehl

Introduction To the Microsoft Bot Framework
Becky Bertram

Javascript Asynchronous Roundup (Promises Promises…)
Mark Meadows

JavaScript Futures: ES2017 and the Road Ahead
Jeff Strauss

Jewelbots: How to Get More Girls Coding!
Jennifer Wadella

Kotlin: What’s in it For You
Douglas Starnes

Learning the Language of HTTP for a Better Data Experience in Your Mobile Apps
Chris Woodruff

Let’s Talk About Mental Health
Arthur Doler

Leveraging Microsoft Azure to enable your Internet of Things
Ralph Wheaton

Linux and Windows Containers, Not All Are Created Equal
Yung Chou

Love and Hate, Having Conversations About Going to the Cloud
Bryan Roberts

Make .NET Great Again!
Sam Basu

Managing Millennials
Jim Drewes

Maximize Professional Growth By Doing Scary Things
Steven Hicks

Mechanics and Moxie: Modernizing Quality Assurance
Kylie Schleicher

Microservice-Powered Applications – It worked for Voltron, it can work for you!
Bryan Soltis

Microservices – A Pattern for Success
David Davids

Microsoft Azure Makes Machine Learning Accessible and Affordable
Douglas Starnes

Migrating from desktop to serverless with AWS
Bryan Nehl

Mobile Development For Web Developers
Justin James

Moving into mobile with Angular 2 and Ionic Framework
Mike Hamilton

Moving into mobile with React Native
Mike Hamilton

Naked and Not Afraid: How to Better Serve Your Clients
Rick Petersen

Neural Networks: The Good Bits
Chase Aucoin

Next-level test-driven development
Alison Hawke

Optimizing Application Performance
Jason Turan

Planet scale data with CosmosDB
Bryan Roberts

Planning for Failure
Jesse Phelps

Practical Security Practices: Threat Modeling
Josh Gillespie

Productivity: How to Get Things Done in this Digital Age
Keith Elder

React for the Uninitiated
Mark Meadows

Refactoring Towards Resilience
Jimmy Bogard

ReSharper: Discover the Secrets
Ondrej Balas

Respond To and Troubleshoot Production Incidents Like an SA
Tom Cudd

Reverse Engineering a Bluetooth Lightbulb
Jesse Phelps

Securing ASP.NET Core APIs and Websites with IdentityServer4
Jeffrey St. Germain

Securing your Applications with Azure AD
Mike Green

Self-Assembling, Self-Healing Systems in the AWS cloud
James Nugent

Serilog: Logging All Grown Up
Brian Korzynski

Serverless JavaScript OMG
Burke Holland

Should I be a generalist or a specialist?
Eric Potter

Should I make the Transition to ASP.NET MVC Core? Will it Hurt?
Mitchel Sellers

Software Development to Leadership
Cori Kristoff

SQL Server For The .NET Developer
Clayton Hoyt

SQL Server Power Hour With Dan and Kathi
Dan Guzman

Strategies for learning React
Ryan Lanciaux

Survival Guide to the Robot Apocalypse – Intro to Deep Learning for Developers
Steve Howard

Swift start on iOS development
Muljadi Budiman

Take Each Day and Work on Making it Better
Dean Furness

Taking Azure Application Insights to the Next Level
Ralph Wheaton

Taming the Tentacles of Octopus
Kevin Fitzpatrick

Teaching Kids Programming
Sarah Phelps

The Business Case for UX
Danielle Cooley

The Hardest Part of Being an Architect: A Death Star Story
Rick Petersen

The Lean & Agile Transformation Playbook
Clint Edmonson

The Modern ASP.NET Tech Stack!
Sam Basu

The Power of Secrets
Sarah Withee

The Reusable JavaScript Revolution
Cory House

The Saboteur in Your Retrospectives: How Your Brain Works Against You
Arthur Doler

The Thrill of the Hunt: The Return to Exploratory Testing
Kylie Schleicher

The Two Question Code Quiz: How to Interview Programmers Effectively
Scott Connerly

To Infinity and Beyond: Build Serverless APIs
Bryan Roberts

TypeScript — JavaScript Reimagined
David Pine

Understanding Azure Resource Templates
Paul Hacker

Unit Testing Strategies & Patterns in C#
Bill Dinger

Visual Studio Code Can Do THAT?!?
Burke Holland

What C# Programmers Need to Know About Pattern Matching
Eric Potter

What Is Data Science?
Ryan Metcalf

What Makes a Good Developer? – Increasing Your Value in a Polyglot World
Eric Lynn

What’s New in ASP.NET Core 2.0?
Scott Addie

What’s New in Java 9
Billy Korando

What’s New in VS 2017 and C# 7
Doug Mair

Why Aren’t There More Women Developers?
Jennifer Wadella

Windows IoT Core Development on a Raspberry Pi
Kevin Grossnicklaus

You Got Your Dev in My Ops, You Got Your Ops in My Dev
Paul Hacker

Your JavaScript Needs Types
Spencer Schneidenbach

Amazon Fire HD 8 Crashing My Wireless Router?!

I took advantage of Amazon Prime day this year and picked up a new Amazon Fire HD 8 tablet. While setting it up, I ran into problems when the wireless connection kept dropping. Others in the family had reported Wifi problems earlier in the day, so I didn’t think too much of it. Rebooted the cable modem and wireless router, but the problems persisted. Figured it was a problem at the cable company and decided to just let it go until the next day.

Unfortunately, the problems persisted into the next day… until I turned off Wifi on the Fire HD 8! It turns out that something about the Fire HD 8 was crashing my wireless router. This could be consistently demonstrated: the router crashed repeatedly every time I turned on Wifi on the Fire HD 8, and recovered when I turned off Wifi.

After doing some online research and finding a number of unusual solutions that were purported to work (make sure to check the “Hide Password” box on the Fire HD 8 before connecting? really?), I was able to track down the real problem (and a solution).

Wireless routers can be configured with a variety of different security options. These options control who has access to the network; it can be left entirely open for anyone to use, or can be secured using a variety of different protocols and encryption strategies.

Two of the strategies are to leave the network open or to use WEP security. Neither are good options: an open network is a bad idea, and WEP is a weak protocol.

Better options are WPA and WPA2, WPA2 being the most secure. My router’s configuration page includes the following description of the security options:

“Use ‘WPA or WPA2’ mode to achieve a balance of strong security and best compatibility. This mode uses WPA for legacy clients while maintaining higher security with stations that are WPA2 capable. Also the strongest cipher that the client supports will be used. For best security, use ‘WPA2 Only’ mode. This mode uses AES cipher. For maximum compatibility, use ‘WPA Only’. This mode uses TKIP cipher.”

Another thing to note is that the WPA2 with AES option allows for the highest wireless rate (generally around 130Mbps). WPA with TKIP is capped at a rate of 56Mbps.

How does all of this relate to the problem I was having with my Amazon Fire HD 8 tablet? My router had been configured as suggested, in ‘WPA or WPA2’ mode, for maximum compatibility. When I changed the configuration to WEP with TKIP only, the problems went away! It seems that something about my router, the Amazon Fire HD 8, and WPA2 with AES was a bad combination.

The solution was to configure the “Guest Zone” on my router, which effectively sets up a second network. I left my original network configured in ‘WPA or WPA2’ mode, so that all of my existing devices could take advantage of the better security and higher wireless throughput rate of WPA2 (assuming they supported it). The new “Guest” network was configured with ‘WPA Only’ and the TPIK cipher. I connected the Fire HD 8 to the “Guest” network, and now all of my devices (including the router!) are able to coexist peacefully together. As far as the lower throughput rate on the Guest network required by the ‘WPA Only’ option, it does not seem to be an issue. I have been able to stream video on the Fire HD 8 from several locations in the house, both near and relatively far from the wireless router.

Hope this information helps someone else!

 

Finding Your Windows System’s Last Boot Time

To find the last boot time of your computer, use the following command:

systeminfo | find “System Boot Time”

It will produce output that looks something like this:

System Boot Time:    11/11/2016, 10:11:21 AM

The systeminfo command sends detailed information about the computer and the operating system to the standard output.  The “|” redirects that output to the find command, which searches it for the string “System Boot Time”.  The find command then outputs the line or lines of the systeminfo output that match the string “System Boot Time”.

This should work on Windows 7 and later, and on Windows Server 2008 and later.

Data Access Framework Comparison

Introduction

For some time now I have been working on a project that utilizes a custom-built data access framework, rather than popular ORM frameworks such as Entity Framework or NHibernate.

While the custom framework has worked well for the project, I had questions about it.  For example, it uses stored procedures to implement basic CRUD operations, and I wondered if inline parameterized SQL statements might perform better.  Also, I wondered about the performance of the custom framework compared to the leading ORMs.

Besides my questions about the custom framework, I recognized the importance of having at least a basic understanding of how to use the other ORM frameworks.

In order to answer my questions about the custom framework and to gain some practical experience with the other ORMs, I created a simple web application that uses each of those frameworks to perform basic CRUD applications.  While executing the CRUD operations, the application times them and produces a summary report of the results.

The code for the test application can be found at https://github.com/mlichtenberg/ORMComparison.

NOTE: I assume that most readers are familiar with the basics of Entity Framework and NHibernate, so I will not provide an overview of them here.

Using the custom framework is similar to Entity Framework and NHibernate’s “database-first” approach.  Any project that uses the library references a single assembly containing the base functionality of the library.  A T4 template is used to generate additional classes based on tables in a SQL Server database.  Some of the classes are similar to EF’s Model classes and NHibernate’s Domain classes.  The others provide the basic CRUD functionality for the domain/model classes. 

For these tests I made a second copy of the custom framework classes that provide the basic CRUD functionality, and edited them to replace the CRUD stored procedures with parameterized SQL statements.

The custom framework includes much less overhead on top of ADO.NET than the popular ORMs, so I expected the tests to show that it was the best-performing framework.  The question was, how much better?

In the rest of this post, I will describe the results of my experiment, as well as some of the optimization tips I learned along the way.  Use the following links to jump directly to a topic.

Test Application Overview
“Out-of-the-Box” Performance
Entity Framework Performance After Code Optimization
     AutoDetectChangesEnabled and DetectChanges()
     Recycling the DbContext
NHibernate Performance After Configuration Optimization
     What’s Up with Update Performance in NHibernate?
Results Summary

Test Application Overview

    A SQL Express database was used for the tests.  The data model is borrowed from Microsoft’s Contoso University sample application.  Here is the ER diagram for the database:

image

 

The database was pre-populated with sample data.  The number of rows added to each table were:

Department: 20
Course: 200
Person: 100000
Enrollment: 200000

This was done because SQL Server’s optimizer will behave differently with an empty database than it will with a database containing data, and I wanted the database to respond as it would in a “real-world” situation.  For the tests, all CRUD operations were performed against the Enrollment table.

Five different data access frameworks were tested:

  1. Custom framework with stored procedures
  2. Custom framework with parameterized SQL statements
  3. Entity Framework
  4. NHibernate
  5. Fluent NHibernate

The testing algorithm follows the same pattern for each of the frameworks:

01) Start timer
02) For a user-specified number of iterations 
03)      Submit an INSERT statement to the database
04)      Save the identifier of the new database record
05) End timer
06) Start timer
07) For each new database record identifier
08)      Submit a SELECT statement to the database
09) End timer
10) Start timer
11) For each new database record identifier
12)      Submit an UPDATE statement to the database
13) End timer
14) Start timer
15) For each new database record identifier
16)      Submit a DELETE statement to the database
17) End timer

Note that after the test algorithm completes, the database is in the same state as when the tests began.

To see the actual code, visit https://github.com/mlichtenberg/ORMComparison/blob/master/MVCTestHarness/Controllers/TestController.cs.

"Out-of-the-Box" Performance

I first created very basic tests for each framework. Essentially, these were the “Hello World” versions of the CRUD code for each framework.  No optimization was attempted.

Here is an example of the code that performs the INSERTs for the custom framework.  There is no difference between the version with stored procedures and the version without, other than the namespace from which EnrollmentDAL is instantiated.

    DA.EnrollmentDAL enrollmentDAL = new DA.EnrollmentDAL();

    for (int x = 0; x < Convert.ToInt32(iterations); x++)
    {
        DataObjects.Enrollment enrollment = enrollmentDAL.EnrollmentInsertAuto
            (null, null, 101, 1, null);
        ids.Add(enrollment.EnrollmentID);
    }

      And here is the equivalent code for Entity Framework:

    using (SchoolContext db = new SchoolContext())
    {
       for (int x = 0; x < Convert.ToInt32(iterations); x++)
        {
            Models.Enrollment enrollment = new Models.Enrollment {
                CourseID = 101, StudentID = 1, Grade = null };
            db.Enrollments.Add(enrollment);
            db.SaveChanges();
            ids.Add(enrollment.EnrollmentID);
        }

    }

    The code for NHibernate and Fluent NHibernate is almost identical.  Here is the NHibernate version:

using (var session = NH.NhibernateSession.OpenSession("SchoolContext"))
{
    var course = session.Get<NHDomain.Course>(101);
    var student = session.Get<NHDomain.Person>(1);

    for (int x = 0; x < Convert.ToInt32(iterations); x++)
    {
        var enrollment = new NHDomain.Enrollment { 
            Course = course, Person = student, Grade = null };
        session.SaveOrUpdate(enrollment);

        ids.Add(enrollment.Enrollmentid);
    }

}

The SELECT, UPDATE, and DELETE code for each framework followed similar patterns. 

    NOTE: A SQL Server Profiler trace proved that the actual interactions with the database were the same for each framework.  The same database connections were established, and equivalent CRUD statements were submitted by each framework.  Therefore, any measured differences in performance are due to the overhead of the frameworks themselves.

        Here are the results of the tests of the “out-of-the-box” code:

      Framework              Operation     Elapsed Time (seconds)
      Custom                 Insert        5.9526039
      Custom                 Select        1.9980745
      Custom                 Update        5.0850357
      Custom                 Delete        3.7785886

      Custom (no SPs)        Insert        5.2251725
      Custom (no SPs)        Select        2.0028176
      Custom (no SPs)        Update        4.5381994
      Custom (no SPs)        Delete        3.7064278

      Entity Framework       Insert        1029.5544975
      Entity Framework       Select        8.6153572
      Entity Framework       Update        2362.7183765
      Entity Framework       Delete        25.6118191

      NHibernate             Insert        9.9498188
      NHibernate             Select        7.3306331
      NHibernate             Update        274.7429862
      NHibernate             Delete        12.4241886

      Fluent NHibernate      Insert        11.796126
      Fluent NHibernate      Select        7.3961941
      Fluent NHibernate      Update        283.1575124
      Fluent NHibernate      Delete        10.791648

      NOTE: For all tests, each combination of Framework and Operation was executed 10000 times.   Looking at the first line of the preceding results, this means that Custom framework took 7.45 seconds to perform 10000 INSERTs.

      As you can see, both instances of the the custom framework outperformed Entity Framework and NHibernate.  In addition, the version of the custom framework that used parameterized SQL was very slightly faster than the version that used stored procedures.  Most interesting however, was the performance for INSERT and UPDATE operations.  Entity Framework and both versions of NHibernate were not just worse than the two custom framework versions, they were much MUCH worse.  Clearly, some optimization and/or configuration changes were needed.

      Entity Framework Performance After Code Optimization

      AutoDetectChangesEnabled and DetectChanges()  

      It turns out that much of Entity Framework’s poor performance appears to have been due to the nature of the tests themselves.  Information on Microsoft’s MSDN website notes that if you are tracking a lot of objects in your DbContext object and call methods like Add() and SaveChanges() many times in a loop, your performance may suffer.  That scenario describes the test almost perfectly.

      The solution is to turn off Entity Framework’s automatic detection of changes by setting AutoDetectChangesEnabled to false and explicitly calling DetectChanges().  This instructs Entity Framework to only detect changes to entities when explicitly instructed to do so.  Here is what the updated code for performing INSERTs with Entity Framework looks like (changes highlighted in red):

      using (SchoolContext db = new SchoolContext())
      {
          db.Configuration.AutoDetectChangesEnabled = false;

          for (int x = 0; x < Convert.ToInt32(iterations); x++)
          {
              Models.Enrollment enrollment = new Models.Enrollment {
                  CourseID = 101, StudentID = 1, Grade = null };
              db.Enrollments.Add(enrollment);
              db.ChangeTracker.DetectChanges();
              db.SaveChanges();
              ids.Add(enrollment.EnrollmentID);
          }
      }

      Here are the results of tests with AutoDetectChangesEnabled set to false:

      Framework           Operation    Elapsed Time (seconds)
      Entity Framework    Insert       606.5569332
      Entity Framework    Select       6.4425741
      Entity Framework    Update       605.6206616
      Entity Framework    Delete       21.0813293

      As you can see, INSERT and UPDATE performance improved significantly, and SELECT and DELETE performance also improved slightly.

      Note that turning off AutoDetectChangesEnabled and calling DetectChanges() explicitly in all cases WILL slightly improve the performance of Entity Framework.  However, it could also cause subtle bugs.  Therefore, it is best to only use this optimization technique in very specific scenarios and allow the default behavior otherwise.

      Recycling the DbContext

      While Entity Framework performance certainly improved by changing the AutoDetectChangesEnabled value, it was still relatively poor. 

      Another problem with the tests is that the same DbContext was used for every iteration of an operation (i.e. one DbContext object was used for all 10000 INSERT operations).  This is a problem because the context maintains a record of all entities added to it during its lifetime.  The effect of this was a gradual slowdown of the INSERT (and UPDATE) operations as more and more entities were added to the context.

      Here is what the Entity Framework INSERT code looks like after modifying it to periodically create a new Context (changes highlighted in red):

      for (int x = 0; x < Convert.ToInt32(iterations); x++)
      {
          // Use a new context after every 100 Insert operations
          using (SchoolContext db = new SchoolContext())
          {
              db.Configuration.AutoDetectChangesEnabled = false;

              int count = 1;
              for (int y = x; y < Convert.ToInt32(iterations); y++)
              {
                  Models.Enrollment enrollment = new Models.Enrollment {
                      CourseID = 101, StudentID = 1, Grade = null };
                  db.Enrollments.Add(enrollment);
                  db.ChangeTracker.DetectChanges();
                  db.SaveChanges();
                  ids.Add(enrollment.EnrollmentID);

                  count++;
                  if (count >= 100) break;
                  x++;
              }
          }
      }

      And here are the results of the Entity Framework tests with the additional optimization added:

      Framework            Operation     Elapsed Time (seconds)
      Entity Framework     Insert        14.7847024
      Entity Framework     Select        5.5516514
      Entity Framework     Update        13.823694
      Entity Framework     Delete        10.0770142

      Much better!  The time to perform the SELECT operations was little changed, but the DELETE time was reduced by half, and the INSERT and UPDATE times decreased from a little more than 10 minutes to about 14 seconds.

      NHibernate Performance After Configuration Optimization

      For the NHibernate frameworks, the tests themselves were not the problem.  NHibernate itself needs some tuning. 

      An optimized solution was achieved by changing the configuration settings of the NHibernate Session object.  Here is the definition of the SessionFactory for NHibernate (additions highlighted in red):

      private static ISessionFactory SessionFactory
      {
          get
          {
              if (_sessionFactory == null)
              {
                  string connectionString = ConfigurationManager.ConnectionStrings
                      [_connectionKeyName].ToString();

                  var configuration = new NHConfig.Configuration();
                  configuration.Configure();

                  configuration.SetProperty(NHConfig.Environment.ConnectionString,
                      connectionString);

                  configuration.SetProperty(NHibernate.Cfg.Environment.FormatSql,
                      Boolean.FalseString);
                  configuration.SetProperty
                     (NHibernate.Cfg.Environment.GenerateStatistics,
                          Boolean.FalseString);
                  configuration.SetProperty
                     (NHibernate.Cfg.Environment.Hbm2ddlKeyWords,
                          NHConfig.Hbm2DDLKeyWords.None.ToString());
                  configuration.SetProperty(NHibernate.Cfg.Environment.PrepareSql,
                          Boolean.TrueString);
                  configuration.SetProperty
                      (NHibernate.Cfg.Environment.PropertyBytecodeProvider,
                          "lcg");
                  configuration.SetProperty
                      (NHibernate.Cfg.Environment.PropertyUseReflectionOptimizer,
                          Boolean.TrueString);
                  configuration.SetProperty
                      (NHibernate.Cfg.Environment.QueryStartupChecking,
                          Boolean.FalseString);
                  configuration.SetProperty(NHibernate.Cfg.Environment.ShowSql, 
                      Boolean.FalseString);
                  configuration.SetProperty
                      (NHibernate.Cfg.Environment.UseProxyValidator, 
                          Boolean.FalseString);
                  configuration.SetProperty
                      (NHibernate.Cfg.Environment.UseSecondLevelCache,
                          Boolean.FalseString);

                  configuration.AddAssembly(typeof(Enrollment).Assembly);
                  _sessionFactory = configuration.BuildSessionFactory();
              }
              return _sessionFactory;
          }
      }

      And here is the InitializeSessionFactory method for Fluent NHibernate, with the equivalent changes included:

      private static void InitializeSessionFactory()
      {
          string connectionString = ConfigurationManager.ConnectionStrings[_connectionKeyName]
              .ToString();

          _sessionFactory = Fluently.Configure()
              .Database(MsSqlConfiguration.MsSql2012.ConnectionString(connectionString).ShowSql())
              .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Enrollment>())
              .BuildConfiguration().SetProperty
                  (NHibernate.Cfg.Environment.FormatSql, Boolean.FalseString)
              .SetProperty(NHibernate.Cfg.Environment.GenerateStatistics,
                  Boolean.FalseString)
              .SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords,
                  NHibernate.Cfg.Hbm2DDLKeyWords.None.ToString())
              .SetProperty(NHibernate.Cfg.Environment.PrepareSql,
                  Boolean.TrueString)
              .SetProperty(NHibernate.Cfg.Environment.PropertyBytecodeProvider,
                  "lcg")
              .SetProperty
                  (NHibernate.Cfg.Environment.PropertyUseReflectionOptimizer,
                      Boolean.TrueString)
              .SetProperty(NHibernate.Cfg.Environment.QueryStartupChecking,
                  Boolean.FalseString)
              .SetProperty(NHibernate.Cfg.Environment.ShowSql, Boolean.FalseString)
              .SetProperty(NHibernate.Cfg.Environment.UseProxyValidator,
                  Boolean.FalseString)
              .SetProperty(NHibernate.Cfg.Environment.UseSecondLevelCache,
                  Boolean.FalseString)
              .BuildSessionFactory();
      }

      The following table gives a brief description of the purpose of these settings:

      Setting                   Purpose
      FormatSql                 Format the SQL before sending it to the database
      GenerateStatistics        Produce statistics on the operations performed
      Hbm2ddlKeyWords           Should NHibernate automatically quote all db object names
      PrepareSql                Compiles the SQL before executing it
      PropertyBytecodeProvider  What bytecode provider to use for the generation of code
      QueryStartupChecking      Check all named queries present in the startup configuration
      ShowSql                   Show the produced SQL
      UseProxyValidator         Validate that mapped entities can be used as proxies
      UseSecondLevelCache       Enable the second level cache

      Notice that several of these (FormatSQL, GenerateStatistics, ShowSQL) are most useful for debugging.  It is not clear why they are enabled by default in NHibernate; it seems to me that these should be opt-in settings, rather than opt-out.

      Here are the results of tests of the NHibernate frameworks with these changes in place:

      Framework                        Operation     Elapsed Time (seconds)
      NHibernate (Optimized)           Insert        5.0894047
      NHibernate (Optimized)           Select        5.2877312
      NHibernate (Optimized)           Update        133.9417387
      NHibernate (Optimized)           Delete        5.6669841

      Fluent NHibernate (Optimized)    Insert        5.0175024
      Fluent NHibernate (Optimized)    Select        5.2698945
      Fluent NHibernate (Optimized)    Update        128.3563561
      Fluent NHibernate (Optimized)    Delete        5.5299521

      These results are much improved, with the INSERT, SELECT, and DELETE operations nearly matching the results achieved by the custom framework.   The UPDATE performance, while improved, is still relatively poor.

      What’s Up with Update Performance in NHibernate?

      The poor update performance is a mystery to me.  I have researched NHibernate optimization techniques and configuration settings, and have searched for other people reporting problems with UPDATE operations.  Unfortunately, I have not been able to find a solution.

      This is disappointing, as I personally found NHibernate more comfortable to work with than Entity Framework, and because it beats or matches the performance of Entity Framework for SELECT, INSERT, and DELETE operations.

      If anyone out there knows of a solution, please leave a comment!

      Final Results

      The following table summarizes the results of the tests using the optimal configuration for each framework.  These are the same results shown earlier in this post, combined here in a single table.

      Framework                        Operation     Elapsed Time (seconds)
      Custom                           Insert        5.9526039
      Custom                           Select        1.9980745
      Custom                           Update        5.0850357
      Custom                           Delete        3.7785886

      Custom (no SPs)                  Insert        5.2251725
      Custom (no SPs)                  Select        2.0028176
      Custom (no SPs)                  Update        4.5381994
      Custom (no SPs)                  Delete        3.7064278

      Entity Framework (Optimized)     Insert        14.7847024
      Entity Framework (Optimized)     Select        5.5516514
      Entity Framework (Optimized)     Update        13.823694
      Entity Framework (Optimized)     Delete        10.0770142

      NHibernate (Optimized)           Insert        5.0894047
      NHibernate (Optimized)           Select        5.2877312
      NHibernate (Optimized)           Update        133.9417387
      NHibernate (Optimized)           Delete        5.6669841

      Fluent NHibernate (Optimized)    Insert        5.0175024
      Fluent NHibernate (Optimized)    Select        5.2698945
      Fluent NHibernate (Optimized)    Update        128.3563561
      Fluent NHibernate (Optimized)    Delete        5.5299521

      And here is a graph showing the same information:

      image

    That Conference 2016–Session Resources

    Last week I had the pleasure of attending the 2016 edition of That Conference.

    It was an all-around excellent experience.  The venue, topics, speakers, sponsors, food, after-hours events, and swag all left little to complain about.  In addition, many technical conferences include areas/times for free-form open discussions led by conference attendees on topics of their choosing, and That Conference is no exception.  That Conference’s version of this was called Open Spaces, and by all accounts it was a success.  While I only took part in a single discussion, I observed that the area designated for those discussions was never not busy.

    Conference experiences can be spoiled by inexperienced or ill-prepared session speakers.  At That Conference I was pleased by the quality of the speakers in all twelve sessions and three keynotes that I attended.  However, there were too many interesting sessions (a good thing!) and too little time (can’t be helped).  Therefore, since returning home I have been watching social media and the conference website in order to compile links to as many of the session materials as possible.

    Here are the links to everything that I have been able to find.  (If you know if others, please post a comment with the links!)

    Against Best Practices – Embracing the Avant Garde for a Weirder Web
    Chelsea Maxwell

    As Seen On TV: Developing Apps for Apple TV and TVOS
    Matthew Soucoup

    Back to the Future => C# 7
    Mike Harris

    Battle of the CLI: Gulp vs. Grunt
    Abbey Gwayambadde

    Be An Expert Xamarin Outdoorsman with the Ultimate Xamarin Toolchain
    Vince Bullinger

    Bear Proof Applications: Using Continuous Security to Mitigate Threats
    Wendy Istanick

    Boost Your Immune System with DevOps
    Michelle Munstedt

    Build and Deploy Your ASP.NET Core Applications… Automatically!
    Brandon Martinez

    Build Your Own Smart Home
    Brandon Satrom

    Building Mobile Games That Make Money
    Scott Davis

    C#: You Don’t Know Jack
    George Heeres

    Clean Architecture: Patterns, Practices, and Principles
    Matthew Renze

    Common T-SQL Mistakes
    Kevin Boles

    Computer Science: The Good Parts
    Jeffery Cohen

    Daring to Develop With Docker
    Philip Nelson

    Date and Time: Odds, Ends, and Oddities
    Maggie Pint

    Domain Driven Data
    Bradley Holt

    Enough Cryptography to be Dangerous
    Steve Marx

    The Experimentation Mindset
    Doc Norton

    Finding Your Way to the App Store
    Matthew Ridley

    From Inception to Production: A Continuous Delivery Story
    Ian Randall

    From Mobile First to Offline First
    Bradley Holt

    Full-Stack ASP.NET MVC Performance Tuning
    Dustin Ewers

    Happy Full-Stack Javascript Campers
    Ryan Niemeyer

    How I Learned To Love Dependency Injection
    James Bender

    Identity Management in ASP.NET Core
    Ondrej Balas

    An Internet Of Beers
    Wade Wegner

    Intro to Typescript
    Jody Gustafson

    Introduction to Angular 2.0
    Jeremy Foster

    Javascript Code Quality
    Md Khan

    Keynote: Family Keynote
    Neely Drake and Emily Davis

    Keynote: From 0 to 100,000: How Particle Failed, then Succeeded, then Scaled
    Zach Supalla

    Keynote: Stop Writing Code
    Keith Casey

    Keynote: You Have Too Much Time
    Jeff Blankenburg

    Mastering Voice UX Featuring Amazon’s Echo (AKA Alexa)
    Chris Pauly

    A Microservices Architecture That Emphasizes Rapid Development
    Rob Hruska

    Microsoft Bot Framework: Hiking Up the Trail of Automation
    David Hauck

    The Millennials R Coming
    Heather Shapiro

    Node.JS Crash Course
    David Neal

    Not Just Arts & Crafts: A Developer’s Guide to Incorporating Lean UX Practices into the Development Process
    Rachel Krause

    Out With the Old, In With the New: A Comparison of Angular 1 and 2
    Tony Gemoll

    Pavlov Yourself!
    Alexandra Feldman

    React Native to the Rescue
    Josh Gretz

    React vs. Angular – Dawn of Changes
    John Ptacek

    ReactJS For Beginners
    Arthur Kay

    Ruby on Rails from 0 to Deploy in 60 Minutes
    Chris Johnson

    Ruby Writing Ruby – Campfire Tales of Metaprogramming
    Sara Gibbons

    Service Bus Summer Camp
    David Boike

    So Many Analytics Tools, Which One Is Right For Me?
    Jason Groom

    Start Your Own Business, Dammit!
    Terra Fletcher

    A Tale of Two Redesigns
    Jess Bertling

    Tell SQL Server Profiler To Take A Hike
    Jes Borland

    Understanding Git, Part 2
    Keith Dahlby

    UX Beyond the UI – How the Rest of Software Development Affects User Experience
    Joe Regan

    Why Your Site Is Slow
    Steve Persch

    Working From Whereever
    Aaron Douglas