I’ve published a small project called Linq Mapper that translates simple LINQ queries between different data sources.  It allows you to write queries against your domain model, but have them run against a different model (typically a data model like LINQ to SQL or Entity Framework).

Currently it expects you to annotate your domain model classes and properties with some attributes, similar to this:

[EntityMapping( "Account" )]
public class Account
{
    [PropertyMapping( "ID", KnownProperty.PrimaryKey )]
    public int Id { get; set; }

    [PropertyMapping( "Name" )]
    public string Name { get; set; }

    [PropertyMapping( "Description" )]
    public string Description { get; set; }

    [AssociationMapping( "Transaction" )]
    public IEnumerable<Transaction> Transactions { get; set; }
}

That simply maps the “Account” model to an “Account” entity; same for the properties.  Notice the AssociationMapping attribute, which tells it a little about associations (relationships).  Here’s another example:

[EntityMapping( "Transaction" )]
public class Transaction
{
    [PropertyMapping( "ID", KnownProperty.PrimaryKey )]
    public int Id { get; set; }

    [AssociationMapping( "Account" )]
    public Account Account { get; set; }

    [PropertyMapping( "Date" )]
    public DateTime Date { get; set; }

    [PropertyMapping( "Payee" )]
    public string Payee { get; set; }

    [PropertyMapping( "Description" )]
    public string Description { get; set; }

    [PropertyMapping( "Amount" )]
    public decimal Amount { get; set; }
}

The query translation is done through an expression tree visitor (derived from .NET 4’s ExpressionVisitor class; note you could use this with .NET 3.5 too but you’d need to “borrow” the code from Reflector first… or ask me to send it :) ).

It can handle most queries you throw at it, but there’s some chance there are holes too (so let me know if you want to contribute any fixes, improvements etc to it).  As a simple example of the Account and Transaction classes described above, you could easily create a query like this:

var accounts = context.CreateQuery<Account>();

var summary = from a in accounts
              select new
              {
                  Name = a.Name,
                  Transactions = from t in a.Transactions
                                 select new
                                 {
                                     Payee = t.Payee,
                                     Amount = t.Amount
                                 }
              };

The neat thing is, only the properties you ask for will be queried for in the data source; it’s just like running a regular LINQ to SQL (or LINQ to Entities) query but using your domain model.

The underlying data model doesn’t need to be a physical data source at all.  It’s quite possible to use this to mock an entire database schema in memory, which is great for testing.  I’ll describe this more in a later post.

The test project is available on CodePlex here, and you can browse or download the source code here.  It’s at an early stage, but it’s proving pretty versatile already.  The bits included are:

  • Cjc.Data.Mapping – The mapping attribute definitions, the expression tree visitor and the gunk needed to make it go.  If there are bugs, this is where they’re likely to be :)
  • SampleDataModel – Sample LINQ to SQL and EntityFramework data model classes.
  • SampleDomainModel – Sample domain model classes (and a little magic dust).
  • DataMappingDemo – Demo project.

Note the demo project selects which data model to use by specifying an assembly and type name…  However this could use any mechanism you choose.

Let me know if you can make any use of it :)

DotNetKicks Image
About these ads