Monday, March 9, 2009

Valuable custom LINQ provider tutorials

There are plenty of useful tutorials on writing a custom LINQ Provider, however I find these two very valuable:

1. Old, good LINQ to LDAP by Bart De Smet

2. Surprisingly complete tutorial by Matt Warren where a LINQ-to-SQL-like custom provider is explained very thoroughly.

Do not also miss the LINQ's Dynamic Query helper and the MetaLINQ to discover other interesting variations on LINQ.

Friday, March 6, 2009

DevExpress XPO - incomplete Linq support

In general, XPO is great. I like it because of two features:

  • the ability to automatically update the database schema when connecting from the new version of the object model
  • the default "mark-as-deleted" way of removing objects 

There's however one scar on its beautiful face - incomplete Linq support.

No matter how fancy the Linq-To-Whatever implementation is - without Skip and Take it can never be fully adopted in enterprise systems. And XPO's implementation of Linq lacks the support of the Skip operation.

I am afraid that this is because XPO's implementation of paging is flawed by design: if you forget about Linq for a second, the only way to paginate is to use the XPPageSelector over your collection.

   1: /* initial collection*/
   2: XPCollection<TheType> ds = new XPCollection<TheType>(TheSession);
   3:  
   4: /* paging */
   5: XPPageSelector ps = new XPPageSelector(ds);
   6:  
   7: ps.PageSize = PageSize;
   8: ps.CurrentPage = PageNumber;
   9:  
  10: return ds;

If you run the above code and in the same time you trace queries which are executed, you'll learn that:



  1. first, the whole collection of objects' identifiers is retrieved from the data source

  2. the page selector selects the identifier subset which refers to the page you select

  3. then, another query retrieves all the columns but only from the selected page of items


   1: /* first query sent by xpo to retrieve all the data */
   2: select N0."OID" from 
   3: "dbo"."X_RejestrDostepu" N0 
   4: where N0."GCRecord" is null order by N0."Data" asc
   5:  
   6: /* xpo engine selects identifiers of objects in selected page */
   7:  
   8: /* another query - 
   9:    selected page is retrieved by manually providing identifiers 
  10: */
  11: exec sp_executesql N'select 
  12: N0."GCRecord",N0."OID", .... ,N0."OptimisticLockField" 
  13: from "dbo"."X_RejestrDostepu" N0
  14: where (N0."GCRecord" is null and N0."OID" 
  15: in (@p0,@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9))',
  16: N'@p0 int,@p1 int,@p2 int,@p3 int,@p4 int,@p5 int,@p6 
  17: int,@p7 int,@p8 int,@p9 int',@p0=31,@p1=32,@p2=33,@p3=34,@p4=35,@p5=36,@p6=37,@p7=38,@p8=39,@p9=40

And if you realize that there are in fact two queries required to retrieve selected page of data, then you imagine how ineffective (difficult?) this could be when implementing Linq's Skip this way!


It's then no surprise that the only answer to the "when the Skip operator will be supported?" is "sorry, Skip is not supported":


http://community.devexpress.com/forums/p/72977/248858.aspx


Edit: if you find this post in early 2010 or later please consider it outdated. Both skip and take are now correcly handled by XPO's Linq provider. I've blogged about it.

C# Puzzle No.13 (advanced)

Using LinqToSQL is fun and speeds up a lot of things. However, there are issues with LinqToSQL which confuse people. Ultimately, some of these people tend to think that LinqToSQL is useless because things that should be obvious are not such obvious. Over a year ago I wrote a short blog entry on one of such basic issues.

Another such "not-so-obvious" thing is the issue of "ordering". One of the common requirements is to be able to order by the name of the property and not by the property itself. For example, if you use ObjectDataSource, then you know that the sorting parameter is passed to the object responsible for data retrieving by name of the parameter.

Let's take a look at two LinqToSQL ordering attempts:

   1: ConcreteDataContext ctx = new ConcreteDataContext();
   2:  
   3: /* this is easy */
   4: var list = from elem in ctx.TheTable
   5:            orderby elem.Property
   6:            select elem;
   7:  
   8: /* this will compile
   9:    however it does not work
  10: */
  11: string PropertyName = "Property";
  12: var list = from elem in ctx.TheTable
  13:            orderby PropertyName
  14:            select elem;

In the example code above, the first linq clause is obvious - the ordering uses the property "Property" in a direct way. However, in in the second clause we use the name of the property.


You are to answer two following questions:


1. Why the second clause does not produce correct results, although it compiles correctly?


2. How is it possible then to build generic linq expressions which sort objects by names of their properties.


By generic I mean that following solution is not acceptable:



   1: switch ( PropertyName )
   2: {
   3:    case "Property":
   4:  
   5:       return from elem in ctx.TheTable
   6:              orderby elem.Property
   7:              select elem;
   8:  
   9:    case "AnotherProperty":
  10:  
  11:       return from elem in ctx.TheTable
  12:              orderby elem.AnotherProperty
  13:              select elem;
  14:  
  15:    ...
  16:  
  17: }