Home > Magiq > Magiq: Playing with linq-to-sql internals

Magiq: Playing with linq-to-sql internals

For Magiq‘s linq-to-sql provider, Magiq-to-sql, I had to work with the internals of linq-to-sql. The truth about it is: Everything is actually internal (and sealed) and you can’t play with it. It’s awfull, period.

Note: if you don’t know what I’m talking about, you can see my previous posts here and here.

So, the only things I had were:

  • An instance of something that implements IQueryable
  • My good friend Reflector
  • A DataContext instance
  • Quick Watch

First of all, I started to look in the “where” queryable I had. The concrete class in linq-to-sql is DataQuery, internal and sealed. Since Magiq providers work like a strategy, I needed a way to say “ok, this IQueryable is mine!”. But since is internal, I can’t ask for the Type (and worst: I can’t access simple things related to linq-to-sql!). So, I asked for the name. I asked for the AssemblyQualifiedName, indeed. (Ugly#1)

private const string DataQueryAssemblyQualifiedName = "System.Data.Linq.DataQuery`1, System.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";

public bool Handles(IQueryable queryable) {
     var type = queryable.GetType();
     return type.IsGenericType &&
              type.GetGenericTypeDefinition()
              .AssemblyQualifiedName == DataQueryAssemblyQualifiedName;
}

Then, I needed the DataContext in which all the stuff should work. Since DataQuery is internal I have to use reflection in order to get it (I will use DynamicMethod or something in the future). (Ugly#2) UPDATE: All the reflection used in Magiq is now solved using DynamicMethod.

The thing is: I didn’t want to recreate the wheel but I wasn’t able to use the actual parsers. Looking to the DataContext API, I realized another thing that should go to the list: IDbCommand GetCommand( IQueryable queryable) method. This command has the parsed sql and the parameters. So it is, due the circumstances, I kind of nice. But it is a DbCommand. I mean, a real one. It uses the database connection in order to create it. And I need it only in order to have the parsed values. (Ugly#3).

Convert a SELECT <<VALUE1 as PROPERTY1, VALUE2 as PROPERTY2,..>> FROM <<TABLE-JOIN-WHERE>> clause to an UPDATE <<TABLE>> <<PROPERTY1 = VALUE1, PROPERTY2 = VALUE2,…>> FROM <<TABLE-JOIN-WHERE>> one is pretty easy. The problem is that in order to came to that, I need a query of this form:


items.Where( condition ).Select(x=> new Items { Property1 = bla, Property2 = ble });

But instead I had a lot of single properties with it value to assign (Remember the final API?). I tried to generate the new expression dynamicaly, but I didn’t want to force the user to have every setter public just because I need the expression (Later, I realize that isn’t possible to create in a query an object that is being mapped). So, I tried to create a anonymous object, something like this:


items.Where( condition ).Select(x=> new { Property1 = bla, Property2 = ble });

The problem is that Anonymous objects are instances of actual classes and I can’t create one of them. So I thougth “ok, I can create the class on the fly using IL…”. Then, “No, I can’t. Or I don’t want, whatever”. So I tried (it’s all about trying, right?) Dynamic Linq. It worked fine, but since it has it own language (mostly like sql) I would have to parse the enitre tree and that’s exactly what I didn’t wanted to do in the first place. Finally, I decide to create one single select per property. Something like: SELECT <<VALUE>> FROM <<TABLE>>. Parsing that I have the actual sql for the value. It is fine if we don’t think it’s a command, but it is. (Ugly#4).

The good news is, as it uses linq-to-sql generated commands, it full supports linq-to-sql (or I expect that).

That’s all for now. In future posts I will talk about the delete and insert implementations and Magiq-to-objects.

Advertisements
Categories: Magiq Tags: , , ,
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: