LINQ to SQL DataContext Identity Mapping

Each LINQ to SQL datacontext we instantiate holds its own identity map (based on Martin Fowlers Identity Map Pattern). This is basically a dictionary with identity keys pointing to entities in memory previously retrieved from the database – within the scope of the datacontext, that is.

In the example below we retrieve two hotels from the database with the same identity and on the same datacontext. The database gets called only ones for our LINQ query. Hotel1 and Hotel2 are pointing to the same object in memory. They are registered in the same identity map.

using System;
using System.Linq;
using Remondo.Database;
 
namespace LinqToSqlIdentityMap
{
    internal class Program
    {
        private static void Main()
        {
            using (var dataContext =
                new HotelsDataContext {Log = Console.Out})
            {
                Hotel hotel1 = dataContext.Hotels.First(h => h.ID == 5);
                Hotel hotel2 = dataContext.Hotels.First(h => h.ID == 5);
 
                Console.WriteLine("Hotel 1 - {0}", hotel1.GetHashCode());
                Console.WriteLine("Hotel 2 - {0}", hotel2.GetHashCode());
 
                Console.ReadKey();
            }
        }
    }
}

LINQ To SQL Identity Map One DataContext

In the example below we retrieve two Hotels from our database with the same identity, but from a different datacontext. Now Hotel1 and Hotel2 are two different objects in memory and registered in two different identity maps. We see the database gets called twice for the same query.

using System;
using System.Linq;
using Remondo.Database;
 
namespace LinqToSqlIdentityMap
{
    internal class Program
    {
        private static void Main()
        {
            using (var dataContext1 =
                new HotelsDataContext {Log = Console.Out})
            using (var dataContext2 =
                new HotelsDataContext {Log = Console.Out})
            {
                Hotel hotel1 = dataContext1.Hotels.First(h => h.ID == 5);
                Hotel hotel2 = dataContext2.Hotels.First(h => h.ID == 5);
 
                Console.WriteLine("Hotel 1 - {0}", hotel1.GetHashCode());
                Console.WriteLine("Hotel 2 - {0}", hotel2.GetHashCode());
 
                Console.ReadKey();
            }
        }
    }
}

LINQ To SQL Identity Map Two DataContext

In the next example we change the name of Hotel 1 on the first datacontext. We call SubmitChanges, so the database has stored the new name for this hotel. However the in-memory hotel object for datacontext 2 still has the old name. We need to call the Refresh method of the second datacontext for its hotel object to retrieve the new name from the database.

using System;
using System.Data.Linq;
using System.Linq;
using Remondo.Database;
 
namespace LinqToSqlIdentityMap
{
    internal class Program
    {
        private static void Main()
        {
            using (var dataContext1 = new HotelsDataContext())
            using (var dataContext2 = new HotelsDataContext())
            {
                Hotel hotel1 = dataContext1.Hotels.First(h => h.ID == 5);
                Hotel hotel2 = dataContext2.Hotels.First(h => h.ID == 5);
 
                PrintHotelNames(hotel2, hotel1);
 
                // Start Logging to the console window from here
                dataContext1.Log = Console.Out;
                dataContext2.Log = Console.Out;
 
                PrintActionTitle("*** Updating Hotel 1 on datacontext 1");
                hotel1.Name = "Hotel de L'Europe";
                dataContext1.SubmitChanges();
 
                PrintHotelNames(hotel2, hotel1);
 
                PrintActionTitle("*** Refreshing Hotel 2 on datacontext 2");
                dataContext2.Refresh(RefreshMode.OverwriteCurrentValues, hotel2);
 
                PrintHotelNames(hotel2, hotel1);
 
                Console.ReadKey();
            }
        }
 
        private static void PrintActionTitle(string actionTitle)
        {
            Console.WriteLine();
            Console.WriteLine(actionTitle);
            Console.WriteLine();
        }
 
        private static void PrintHotelNames(Hotel hotel2, Hotel hotel1)
        {
            Console.WriteLine("Hotel 1 - {0}", hotel1.Name);
            Console.WriteLine("Hotel 2 - {0}", hotel2.Name);
        }
    }
}

LINQ To SQL Identity Map Two DataContext Update Refresh

LINQ to SQL Insert Associations Example

Adding associated / related entities with LINQ to SQL is a breeze. In the snippet below we add a new TaskList with a new Task (‘Refactor’) for a specific Employee. LINQ to SQL keeps track of the associations and adds them as expected. Note there is no direct attachement needed for the TaskList object to the datacontext. It’s added to the database using some LINQ to SQL magic ;-).

using System;
using System.Linq;
using Remondo.Database;
 
namespace LinqToSqlAssociations
{
    internal class Program
    {
        private static void Main()
        {
            using (var dataContext =
                new RemondoDataContext {Log = Console.Out})
            {
                Employee employee =
                    dataContext.Employees
                        .First(e => e.Name.StartsWith("Leon"));
 
                var task = new Task {Name = "Refactor"};
 
                new TaskList
                    {
                        Employee = employee,
                        Task = task,
                    };
 
                dataContext.SubmitChanges();
 
                Console.ReadKey();
            }
        }
    }
}

LINQ To SQL Associations Console

LINQ to SQL Insert, Update and Delete Example

Quick snippet below as a reminder of the most basic CUD operations in LINQ to SQL. We insert new entities with InsertOnSubmit on the specific entity collection in the datacontext. We delete existing entities the same way with the use of DeleteOnSubmit. We update existing entities by changing their properties.

All operations are stored in the datacontext, which operates as a Unit of Work. Once we call SubmitChanges on the datacontext, all operations are committed in a transaction. If one operation fails all are rolled back.

In the example below we perform some CUD operations on a Employee entity.

using System;
using System.Linq;
using Remondo.Database;
 
namespace LinqToSqlCud
{
    internal class Program
    {
        private static void Main()
        {
            using (var dataContext =
                new RemondoDataContext {Log = Console.Out})
            {
                CreateEmployee(dataContext);
                UpdateEmployee(dataContext);
                DeleteEmployee(dataContext);
 
                dataContext.SubmitChanges(); // Commit Transaction
            }
 
            Console.ReadKey();
        }
 
        private static void CreateEmployee(RemondoDataContext dataContext)
        {
            Department department =
                (from d
                     in dataContext.Departments
                 where d.Name == "Design"
                 select d).First();
 
            Gender gender =
                (from g
                     in dataContext.Genders
                 where g.Name == "Female"
                 select g).First();
 
            var employee =
                new Employee
                    {
                        Department = department,
                        Gender = gender,
                        Name = "Lian Keaton",
                        HireDate = DateTime.Now,
                    };
 
            dataContext.Employees.InsertOnSubmit(employee);
        }
 
        private static void UpdateEmployee(RemondoDataContext dataContext)
        {
            IQueryable<Employee> query =
                from e
                    in dataContext.Employees
                where e.Name.StartsWith("Leon")
                select e;
 
            Employee employee = query.FirstOrDefault();
 
            if (employee != null)
                employee.HireDate = new DateTime(2000, 1, 1);
        }
 
        private static void DeleteEmployee(RemondoDataContext dataContext)
        {
            IQueryable<Employee> query =
                from e
                    in dataContext.Employees
                where e.Name.StartsWith("Stewart")
                select e;
 
            Employee employee = query.FirstOrDefault();
 
            if (employee != null)
                dataContext.Employees.DeleteOnSubmit(employee);
        }
    }
}

LINQ To SQL Cud Operations Console

LINQ to XML Namespace Example

We use a XML namespace to avoid name conflicts. With a namespace we can more specifically point to an element in a XML structure. In LINQ to XML a namespace is represented by the XNamespace class. In the code snippet below we simply add a fictive namespace to the list of cars we created in the previous example.

using System.Xml.Linq;
 
namespace XmlDocConsole
{
    internal class Program
    {
        private static void Main()
        {
            XNamespace ns = "http://remondo.net/xmlns/cars";
           
            var xmlDocument =
                new XDocument(
                    new XElement(
                        ns + "cars",
                        new XElement(
                            ns + "car", "Toyota",
                            new XAttribute(
                                "type", "Aygo VTTi Cool")),
                        new XElement(
                            ns + "car", "Ferarri",
                            new XAttribute(
                                "type", "308 GTS")),
                        new XElement(
                            ns + "car", "Dodge",
                            new XAttribute(
                                "type", "Viper ACR"))
                        )
                    );
 
            xmlDocument.Save("Cars.xml");
        }
    }
}

The resulting XML document shows the added namespace. Notice the namespace is mentioned only once for all elements in the document.

<?xml version="1.0" encoding="utf-8"?>
<cars xmlns="http://remondo.net/xmlns/cars">
  <car type="Aygo VTTi Cool">Toyota</car>
  <car type="308 GTS">Ferarri</car>
  <car type="Viper ACR">Dodge</car>
</cars>

We can declare the namespace even more specific by defining a namespace prefix for the root node. We can then reference this prefix throughout the document. We do this by giving the xmlns attribute (XNamespace.Xmlns) a prefix name and point it to the namespace. We us “spec” as a prefix in the example below. The resulting XML document shows the added namespace prefix.

xmlDocument.Root.SetAttributeValue(XNamespace.Xmlns + "spec", ns);
xmlDocument.Save("Cars.xml");
<?xml version="1.0" encoding="utf-8"?>
<spec:cars xmlns:spec="http://remondo.net/xmlns/cars">
  <spec:car type="Aygo VTTi Cool">Toyota</spec:car>
  <spec:car type="308 GTS">Ferarri</spec:car>
  <spec:car type="Viper ACR">Dodge</spec:car>
</spec:cars>

Simple LINQ to XML Create and Parse Example

In the System.Xml.Linq namespace we find a lot of handy classes for creating and manipulating XML structures and files. XDocument respresents a complete XML structure with nodes (XNode) being elements (XElement) having attributes (XAttribute).

The codesnippet below shows some basic use of these LINQ to XML Classes.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
 
namespace XmlDocConsole
{
    internal class Program
    {
        private static void Main()
        {
            var xmlDocument =
                new XDocument(
                    new XElement(
                        "cars",
                        new XElement(
                            "car", "Toyota",
                            new XAttribute(
                                "type", "Aygo VTTi Cool")),
                        new XElement(
                            "car", "Ferarri",
                            new XAttribute("type", "308 GTS")),
                        new XElement(
                            "car", "Dodge",
                            new XAttribute("type", "Viper ACR"))
                        )
                    );
 
            xmlDocument.Save("Cars.xml");
 
            XElement loadedElement =
                XElement.Load("Cars.xml");
 
            IEnumerable<XElement> carList =
                loadedElement.Elements("car");
 
            var cars = from c in carList
                       let xAttribute = c.Attribute("type")
                       select
                           new
                               {
                                   CarName = c.Value,
                                   CarType = xAttribute.Value
                               };
 
            foreach (var car in cars)
            {
                Console.WriteLine("{0} {1}",
                                  car.CarName,
                                  car.CarType);
            }
 
            Console.ReadKey();
        }
    }
}

Resulting in the following XML document and output.

<?xml version="1.0" encoding="utf-8"?>
<cars>
  <car type="Aygo VTTi Cool">Toyota</car>
  <car type="308 GTS">Ferarri</car>
  <car type="Viper ACR">Dodge</car>
</cars>

LINQ to XML Cars Console

LINQ to SQL Executing SQL or Stored Procedures

It’s sometimes not possible to use LINQ to query to a database or for some reason we want to execute a SQL query statement from within our code. That’s possible by using the DataContext ExecuteQuery or ExecuteCommand methods. The first returns a IEnumerable with entities, while the latter returns a scalar value.

In the example below we query a simple company database for all the male employees ordered by hiredate. We print the employee name and hiredate to the console.

using System;
using System.Collections.Generic;
using Remondo.Database;
 
namespace ExecuteSqlConsole
{
    internal class Program
    {
        private static void Main()
        {
            var dataContext = new RemondoDataContext();
 
            IEnumerable<Employee> employees =
                dataContext.ExecuteQuery<Employee>(
                    "SELECT * FROM Employee " +
                    "WHERE Gender_ID = {0} " +
                    "ORDER BY HireDate",
                    1);
 
            foreach (Employee employee in employees)
            {
                Console.WriteLine(
                    "{0,-24} since {1:yyyy}",
                    employee.Name,
                    employee.HireDate.Date);
            }
 
            Console.ReadKey();
        }
    }
}

Calling Stored Procedures

We can call a Stored Procedure by adding it to the designsurface of the DataContext. We created the same query in a stored procedure called sp_GetEmployeesByGenderOrderedByHireDate. By default this method returns an ISingleResult of some auto-generated type.

Stored Procedure Properties AutoGenerated Type

In this case we want some list of Employee back, so we set the Return Type property of the stored procedure method to the type of Employee. A warning appears telling us this can’t be undone. Oh well.

Message Warning Changing AutoGenerated Type

We can now call our stored procedure from code and iterate through the result set of employees. The output to the console from both the sql query and stored procedure implementations is as expected.

using System;
using System.Data.Linq;
using Remondo.Database;
 
namespace ExecuteSqlConsole
{
    internal class Program
    {
        private static void Main()
        {
            var dataContext = new RemondoDataContext();
 
            ISingleResult<Employee> employees = dataContext
                .sp_GetEmployeesByGenderOrderedByHireDate(1);
 
            foreach (Employee employee in employees)
            {
                Console.WriteLine(
                    "{0,-24} since {1:yyyy}",
                    employee.Name,
                    employee.HireDate.Date);
            }
 
            Console.ReadKey();
        }
    }
}

ExecuteQuery Console

LINQ to SQL Single Table Inheritance Example

With LINQ to SQL we can get model inheritance with filtered mapping, called Single Table Inheritance. We do this by applying a discriminator value to the derived classes. By mapping this value LINQ to SQL knows to instantiate the appropriate base or derived class.

In this example we have a Car base class with the derived types SportsCar and ElectricHybridCar. All cars have a Brand name, but the SportsCar and ElectricHybridCar have some specific properties. The Car base has the discriminator value we mentioned above. It’s a simple character field.

LINQ To SQL Cars Class Hierarchy

We set the discriminator value by configuring the inheritance properties. In this case we clicked the arrow between Car and SportsCar and set the Derived Class Discriminator Value to “S” for SportsCar and the Base Class Dicriminator to “C” for Car. In the Discriminator Property we select the name of the column in our table we use for storing the discriminator values. We do the same for the ElectricHybricCar inheritance properties, this time with the discriminator value “E”.

SportsCar Inheritance Properties Discriminator

We use only one Car table in SQL server to store all the properties of our cars.

Car SQL Single Table

To test if LINQ to SQL actually gives us different types of Cars, SportsCars and ElectricHybridCars back based on the discriminator, we build a simple console application. Iterating through the complete list we print out the specific type of car to the console.

using System;
using System.Linq;
using Remondo.Database;
 
namespace CarsLinqToSqlInheritance
{
    internal class Program
    {
        private static void Main()
        {
            var dataContext =
                new CarsDataContext();
 
            IQueryable<Car> cars =
                dataContext.Cars;
 
            foreach (Car car in cars)
            {
                Console.WriteLine("{0}",
                    car.GetType().FullName);
            }
 
            Console.ReadKey();
        }
    }
}

And indeed… ;-)

LINQ To SQL Single Table Inheritance Console

LINQ to SQL Lazy Loading Example with DataLoadOptions

By default LINQ to SQL is lazy. It defers loading of data until the very first moment it is needed by your application. This behavior makes it possible to keep adding peaces to our query until we are ready to fire a SQL statement to the database. It can also lead to problems and nasty fights with your DBA if you fire hundreds of queries to the db while iterating through some list. This can be prevented by thinking about when to load certain parts of your query and specifying this in the DataLoadOptions of your DataContext.

To illustrate this we have the example below with a simple database of a company in LINQ to SQL classes.

Remondo Company Database

In our application we query for a list of all our female employees ordered descending by their name. We print a list to the console with the Employee name, gender and the building of the department where they work.

In our RemondoDataContext we log all SQL statements to the console. I’ve added some color formatting to point out where LINQ to SQL actually fires of a SQL statement to the database. All data output is shown in white. The green area shows all LINQ to SQL activity to the database with the iteration entry included. The red area show all activity after the first call to the database. As we run our code as shown below, we see a lot of deferred calls (red) in the output on the console.

using System;
using System.Linq;
using Remondo.Database;
 
namespace Remondo.LinqToSqlConsole
{
    internal class Program
    {
        private static void Main()
        {
            // The GREEN area
            Console.ForegroundColor = ConsoleColor.DarkGreen;
 
            var dataContext =
                new RemondoDataContext
                    {
                        Log = Console.Out,
                    };
 
            IOrderedQueryable<Employee> employees =
                dataContext.Employees
                    .Where(g => g.Gender.Name == "Female")
                    .OrderByDescending(e => e.Name);
 
 
            foreach (Employee employee in employees)
            {
                // The RED area
                Console.ForegroundColor = ConsoleColor.DarkRed;
 
                string name = employee.Name;
                string gender = employee.Gender.Name;
                string building = employee.Department.Building.Name;
 
                // Data output in WHITE
                Console.ForegroundColor = ConsoleColor.White;
                Console.WriteLine(
                    "{0}\t{1}\t{2}",
                    name,
                    gender,
                    building);
            }
 
            Console.ReadKey();
        }
    }
}

Remondo Company Female List No DataLoadOptions

That’s too lazy for my taste :-| . What we clearly want here is a result set with gender and building joined on the first call of the iteration. We can do this by specifying up front what the LINQ to SQL must load when we ask for our Employee list the first time. We can do this by setting the DataLoadOptions of the DataContext on a per context basis. With the LoadWith method of the DataLoadOptions object we specify to load Gender and Building with each Employee. We also need to load Department for our Building name.

using System;
using System.Data.Linq;
using System.Linq;
using Remondo.Database;
 
namespace Remondo.LinqToSqlConsole
{
    internal class Program
    {
        private static void Main()
        {
            Console.ForegroundColor = ConsoleColor.DarkGreen;
 
            var dataLoadOptions = new DataLoadOptions();
            dataLoadOptions.LoadWith<Employee>(e => e.Department);
            dataLoadOptions.LoadWith<Employee>(e => e.Gender);
            dataLoadOptions.LoadWith<Department>(d => d.Building);
 
            var dataContext =
                new RemondoDataContext
                    {
                        Log = Console.Out,
                        LoadOptions = dataLoadOptions
                    };
 
            IOrderedQueryable<Employee> employees =
                dataContext.Employees
                    .Where(g => g.Gender.Name == "Female")
                    .OrderByDescending(e => e.Name);
 
 
            foreach (Employee employee in employees)
            {
                ConsoleColor prevColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.DarkRed;
 
                string name = employee.Name;
                string gender = employee.Gender.Name;
                string building = employee.Department.Building.Name;
 
 
                Console.ForegroundColor = ConsoleColor.White;
                Console.WriteLine(
                    "{0}\t{1}\t{2}",
                    name,
                    gender,
                    building);
 
                Console.ForegroundColor = prevColor;
            }
 
            Console.ReadKey();
        }
    }
}

Checking out the results in the console we see that LINQ to SQL joined the gender, department and building up front as expected.

Remondo Company Female List With DataLoadOptions