Archive for July, 2008

Dynamic LINQ to SQL

Friday, July 25th, 2008

 I came across the following statement about LINQ to SQL on a developer forum the other day:

I think the general consensus is this: it’s good if you know the query beforehand and what type of object you’re going to get back on execution, but if the query is dynamic and/or large then it’s not well suited.”

I thought I would kick off this blog by challenging this statement with some simple examples:

The contributor was partly referring to his belief that it was not possible to do anything similar to dynamic SQL using LINQ to SQL and in fact posted a challenge to do in LINQ to SQL the equivalent of the following dynamic SQL:

string dynamicSQL = ” SELECT ” +  <someCols>  + ”  FROM ” + <someTable> + ” WHERE ” + <someCondition> + ” ORDERBY ” + <orderBy>;

So we will look at how this can be done using LINQ to SQL.

Before looking at this it’s useful to observe that when you dynamically create the <someCondition> for the WHERE clause you would need to distinguish between types when constructing it dynamically. For example:

WHERE Quantity = 3 AND City=’London’   (Assuming Quantity is a number of some type)

You need to know that Quantity is a number and City is a string in order to correctly construct the SQL WHERE clause. What I am getting at is that when constructing dynamic SQL you have to be somewhat aware of what types you are dealing with.

The first thing to remember is that when we construct a LINQ to SQL query, that query is in fact stored as an expression tree. LINQ to SQL uses this expression tree to generate SQL which is sent to the database.

So the starting point for doing dynamic LINQ to SQL is to look at the System.Linq.Expressions namespace.

The System.Linq.Expressions namespace contains classes, interfaces and enumerations that enable language-level code expressions to be represented as objects in the form of expression trees. It enables us to directly manipulate expression trees at runtime. Manipulating expression trees at runtime allows us to create LINQ to SQL queries dynamically.

However, creating LINQ to SQL expression trees directly is not very convenient and is a none trivial task. What would be nice is to have the ability to convert a string representation of a LINQ to SQL query that can be parsed into an expression tree.

As it happens, there is a Dynamic Query Library written in C# that does precisely this and it is available at:

C# Dynamic Query Library (included in the \LinqSamples\DynamicQuery directory)

(The samples also include the NorthwindMapping project which contains the mapping classes for the Northwind database. The examples here are against this mapping.)

If you look in this library (System.Linq.Dynamic) you will see that it makes extensive use of the System.Linq.Expressions and System.Reflection namespace to implement its functionality.

Using this library we are able to construct a potentially fully dynamic LINQ to SQL query.

I will use as my example the LINQ query:

 

            var query =

                from c in db.Customers

                where c.City == “London” && c.Orders.Count >= 10

                select new { Name = c.CompanyName, Phone = c.Phone };

 

expressed here in the C# LINQ syntax. Or:

 

            var query =

                 db.Customers

                    .Where(c => c.City == “London” && c.Orders.Count >= 10)

                    .OrderBy(c=>c.CompanyName)

                    .Select(c => new { Name = c.CompanyName, Phone = c.Phone });

 

expressed here using extension methods. These two queries equate to the same thing.

The System.Linq.Dynamic namespace basically provides a number of overloads to the extension methods for the IQueryable<T> and IQueryable interfaces that accept string representations of lambda expressions. For example the signatures for the Where extension methods are:

 

        public static IQueryable<T> Where<T>(

                this IQueryable<T> source,

                string predicate, params object[] values) {}

and

        public static IQueryable Where<T>(

                this IQueryable source,

                string selector, params object[] values) {}

 

Of course we must make these extensions available by including the using statement:

using System.Linq.Dynamic;

Using these overloaded extension methods we can re-write the above query using string representations like so:

string connString =

@”Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated

                                Security=True”;

Northwind db = new Northwind(connString);

Assembly asm = Assembly.GetAssembly(typeof(Northwind));

var q = db.GetTable(asm.GetType(“NorthwindMapping.Customer”))

.Where(“City == @0 and Orders.Count >= @1″, “London”, 10)

.OrderBy(“CompanyName, City”)

.Select(“New(CompanyName as Name, Phone)”);

 

I have used the db.GetTable(asm.GetType(“NorthwindMapping.Customer”))

statement to get the mapping object dynamically too, however the extension methods have taken care of the rest.

 

 

Everything is expressed as strings with the exception that the parameters for the Where clause need to be the correct type, or at least of types that are implicitly convertible to the correct type. However as I mentioned before, you would need some type awareness when constructing an SQL WHERE clause too.

I could put this into a general purpose method:

        public static IQueryable FullDynamic(

            System.Data.Linq.DataContext dc,           

            string tableName,

            string orderBy,

            string select,

            string wherePredicate,

            params object[] whereValues

            )

        {

            IQueryable q = dc.GetTable(

                    Assembly.GetAssembly(dc.GetType()).GetType(tableName))

                .Where(wherePredicate, whereValues)

                .OrderBy(orderBy)

                .Select(select);

            return q;

        }

 

And call it thus:

            IQueryable q = FullDynamic(

                    db,

                    “NorthwindMapping.Customer”,

                    “CompanyName, City”,

                    “New(CompanyName as Name, Phone)”,

                    “City == @0 and Orders.Count >= @1″,

                    “London”, 10);

 

            foreach (System.Linq.Dynamic.DynamicClass item in q)

            {

                Console.WriteLine(item);

            }

 

I would need to do a little more work on this to enable changing the direction of the order by, but I think that would be about all to answer the challenge fully.

 As you can see the resulting items from the dynamic query inherit from the System.Linq.Dynamic.DynamicClass abstract type.

            foreach (System.Linq.Dynamic.DynamicClass item in query2)

            {

 

                PropertyInfo[] props = item.GetType().GetProperties(BindingFlags.Instance |

                                BindingFlags.Public);

                StringBuilder sb = new StringBuilder();

                sb.Append(“{”);

                for (int i = 0; i < props.Length; i++)

                {

                    if (i > 0) sb.Append(“, “);

                    sb.Append(props[i].Name);

                    sb.Append(“=”);

                    sb.Append(props[i].GetValue(item, null));

                }

                sb.Append(“}”);

                Console.WriteLine(sb.ToString());

            }

 

This demonstrates that you can use reflection to inspect the resulting object graph at runtime – nothing new here, just straight forward use of reflection. In fact this code is taken from the ToString() overload of the System.Linq.Dynamic.DynamicClass abstract type.

I hope this is helpful. In my next article I will look at the other issue raised, of large or complex queries in LINQ to SQL.

 

ADO.NET Entity Framework - my “getting started notes” - Part One

Thursday, July 10th, 2008

I am just getting started with the ADO.NET Entity Framework myself and I thought I’d share things about the experience as I go. Who knows, it might be of use to someone out there! Please, if you see something here that is not correct then let me know.

I found the following article a useful read for starters, although some of the detail is a little out of date I think. It’s a good overview if you need one:

http://msdn.microsoft.com/en-us/magazine/cc163399.aspx

Visual Studio has a visual designer to build entity models and it generates a single EDMX file which it will generate code from using the EntityModelCodeGenerator custom tool.

There is a project called “Sample EDMX Code Generator” (source code available):

http://code.msdn.microsoft.com/sampleedmxcodegen

which can also generate code from EDMX files. The project overview says:

The goal of the Sample EDMX Code Generator is to provide you with enough insight into how the ADO.NET Entity Designer generates code in Visual Studio and hopefully give you a head start with some sample source code.
SampleEdmxCodeGenerator is not intended for production use; instead, it demonstrates custom tool extensibility via SingleFileGenerator, code generation APIs, code generation events and EDM metadata APIs. The sample is also somewhat incomplete on error handling and has not been tuned for performance, stress, etc.

The Entity Framework Samples

http://code.msdn.microsoft.com/EFQuerySamples

project uses separate entity model files however:

·         Conceptual - CSDL

·         Mapping - MSL

·         Logical – SSDL

In VS these don’t appear to have a designer and so one cannot see a visual representation of the model in VS.

It would appear that the EDMX file combines the CSDL, MSL and SSDL files into one file. The XML namespaces (xmlns) in the EDMX file sections are the same as those in the individual files. It also contains additional sections used by the VS designer.

The CSDL defines the entities and the relationships as the application’s business layer will know them. The EntityModelCodeGenerator custom tool will generate code, classes from the CSDL, that represent the domain model. 

In VS the custom tool can be invoked manually from the context menu of the EDMX or CSDL file in solution explorer and or a separate CSDL file - select “Run Custom Tool” - it will normally be set to run the  EntityModelCodeGenerator custom tool, although you can of course change this.

SSDL

The SSDL file or the SSDL section of the EDMX file defines the structure of the relational data in the database.

MSL

The MSL file or the MSL section of the EDMX file contains the direct map from the CSDL to the SSDL.

The CSDL, SSDL and MSL are collectively called the EDM – Entity Data Model.

If you generate an EDM from a database and immediately open the CSDL and SSDL files without making modifications to them, you will find that they are similar because the models are generated directly from the database and the conceptual model is mapped directly to the logical store.

This, of course, does not demonstrate the capabilities of the EDM. At this point the EDM looks very similar to what we would have when creating entities and mappings for LINQ to SQL – just a one to one mapping. LINQ to SQL entity mapping is capable of doing a little more; it supports Table per Hierarchy (TPH), where multiple classes in a hierarchy are mapped to a single table using a discriminator column to determine the specific type of each row/instance (this is a very common database inheritance mapping). One can do this using EF also of course. However, we can see that the EDM allows us to separate the conceptual model from the database model and to connect the two using a mapping.

The real power of the EDM from the OO programmers point of view, then, is dependent on its mapping capabilities. I will be looking at Just how close our conceptual model can be to our ideal OO design for a business domain and yet be usefully mapped to the data model with EF. To me that is the key to EF and it’s usefulness.

Clearly EF intends to go further than the current crop of OR mapping tools in that it is clearly aiming at bridging the object to relational storage impedance mismatch in a different way.

How well it does this remains to be seen…………!!

Composable LINQ to SQL

Wednesday, July 9th, 2008

In LINQ to SQL, queries can be composed. We can use this ability to create dynamic queries. For example:

            Northwind db = new Northwind(connString);

 

            var query =

                from c in db.Customers

                where c.City == “London”

                select c;

 

            Console.WriteLine(db.GetCommand(query).CommandText);

 

            if (true)  // Some condition

            {

                query =

                    from c in query

                    where c.ContactTitle == “Sales Representative”

                    select c;

            }

 

            Console.WriteLine(db.GetCommand(query).CommandText);

 

            /*

            SELECT

                [t0].[CustomerID], [t0].[CompanyName],

                [t0].[ContactName], [t0].[ContactTitle],

                [t0].[Address], [t0].[City], [t0].[Region],

                [t0].[PostalCode], [t0].[Country],

                [t0].[Phone], [t0].[Fax]

            FROM [dbo].[Customers] AS [t0]

            WHERE ([t0].[ContactTitle] = @p0) AND ([t0].[City] = @p1)

            */

 

 

            if (true)

            {

 

                query =

                    (

                    from c in query

                    from o in c.Orders

                    where o.ShipCity == “Colchester”

                    select c

                    ).Distinct();

            }

 

            Console.WriteLine(db.GetCommand(query).CommandText);

 

            /*

            SELECT DISTINCT

                [t0].[CustomerID], [t0].[CompanyName],

                [t0].[ContactName], [t0].[ContactTitle],

                [t0].[Address], [t0].[City], [t0].[Region],

                [t0].[PostalCode], [t0].[Country],

                [t0].[Phone], [t0].[Fax]

            FROM [dbo].[Customers] AS [t0], [dbo].[Orders] AS [t1]

            WHERE ([t1].[ShipCity] = @p0)

                AND ([t0].[ContactTitle] = @p1)

                AND ([t0].[City] = @p2)

                AND ([t1].[CustomerID] = [t0].[CustomerID])         

            */

            foreach (var cust in query)

            {

                Console.WriteLine(cust);

            }

Cool eh!

This can be done because query is an expression tree and the SQL is only generated from the expression tree and the resulting SQL executed when we start to enumerate the query.