Developing Linq to LLBLGen Pro, part 8

(This is part of an on-going series of articles, started here)

Today I managed to arrive back at the point I stopped with my current code base a couple of weeks ago to re-implement the expression tree reduction code. I'm not totally done with re-connecting the wires of the outer interface code to the inner execution engine, but that's a minor detail. A lot of work is still ahead of me, but I've more confidence in finishing it with a satisfying framework than I have had before during this project so far.

To illustrate what expression tree reduction looks like, I'll show you some screenshots from my expression tree visualizer, which is a reworked and enhanced form based on the expression tree visualizer in the C# examples shipped with VS.NET 2008. I've added to this visualizer a pseudo-SQL engine from our own debugger visualizers shipped with LLBLGen Pro so it's easier to see what the relation objects and predicate objects result in. (I use a custom Windows XP theme, so the screen might look a little unorthodox, so no, it's not linux )

The query which is shown as expression trees is the following one, which is pretty bogus but is solely used to check roughly if the code I had in mind even works out the way I thought it would. As you can see from the screenshots, it ends up in a nice QueryExpression, which is the last Expression based class a tree will end up in in my code so I can hand over this object with all its internal data to the execution engine which will simply grab the data inside it and pass it on to the LLBLGen Pro runtime library.

// C#
string city = "Munchen";
var q = from c in metaData.Customer
	join o in metaData.Order on c.CustomerId equals o.CustomerId
	join od in metaData.OrderDetail on o.OrderId equals od.OrderId
	where c.City == city && c.Country == "Germany"
	&& o.EmployeeId == 2 && (od.Quantity * od.UnitPrice) > 500
	select (o.EmployeeId > 10);

My current code can recognize predicates, field expressions, joins (not group joins yet), can evaluate local variables into values used into predicates, projections of single fields and entity projections. This is all embedded into the query above. The screenshots are below. I've made thumbnails of the images so the post stays rather small in size. Click a thumbnail to enlarge the image.

State 0, start state
State 1, Aliases have been assigned to sources, joins have been given their own expressions
State 2, Entities and entity fields have been recognized, as well as constants referring to variables
State 3, LLBLGen Pro field expressions have been recognized
State 4, Predicates and predicate expressions have been recognized
State 5, Joins and selects have been evaluated and combined
State 6, The final tree has been reduced by combining select expressions

There will follow more states and likely this won't be the final order of events. However you can see clearly how the tree gets reduced by recognizing subtrees and replacing these subtrees with a single expression object or other subtree which is easier to handle later on.

Also, for kicks, please pay attention to the expression in text form in the start state's screenshot. 10 to 1 you won't recognize the original query in that.

7 Comments

  • What are you using to enhance your WinApps? The buttons in top-right...

  • The 2 buttons at the left, you mean? THose are from ultramon. I have a dual monitor setup, and these 2 buttons are added to every application so you can move the app quickly to another monitor

  • And what about the rest of the skin? Window Blinds? What theme you're using?

  • Normal XP skin, I use a patched uxtheme.dll to run custom skins (as MS stupidly forbid to run custom skins on XP for no sane reason): GUIRelax, and then the subtheme 'skyman'. Got it from devianart I think.

    (funny how screenshots which show the result of a lot of complex code on expression trees results in a discussion about a windows theme ;))

  • Hehehehe, I'd never dare to go into a discussion with you! ;)

  • You say "[your] current code can recognize predicates, field expressions, joins (not group joins yet), can evaluate local variables into values used into predicates, projections of single fields and entity projections" - this is fantastic as it potentially means that a developer won't have to do all the predicatebucket and relationsToUse setup stuff. I would love to find out whether you will also be able to translate db function calls in to your DbFunction syntax, for example an rtrim(c.City)(I am not even sure if LINQ specs allow this):

    string city = "Munchen";
    var q = from c in metaData.Customer
    join o in metaData.Order on c.CustomerId equals o.CustomerId
    join od in metaData.OrderDetail on o.OrderId equals od.OrderId
    where rtrim(c.City) == city && c.Country == "Germany"
    && o.EmployeeId == 2 && (od.Quantity * od.UnitPrice) > 500
    select (o.EmployeeId > 10);

  • rtrim will be present in the expression tree as a MethodCall to 'rtrim', with parameter c.City. The Linq provider then has to convert that method call to a DB Function call.

    (the correct syntax will be something like:
    where c.City.RTrim()

    That's a big painpoint though: how far will you go in implementing DB function mappings? For strings it's perhaps obvious, but for every db the functions are different (and not every db supports the same functions).

    The linq relations/filter stuff is less flexible and less powerful, as you don't get the hold of how it will end up in SQL. So for example if you want to do a left join on a custom filter with a predicate, calling a UDF, it's not said that that's possible with Linq, it is with llblgen pro's own query syntaxis. We'll keep that around so users have a choice.

Comments have been disabled for this content.