EntityFramework query manipulation, db provider wrapping, db expression trees

c# entity-framework-4 expression expression-trees localization

Question

I'm trying to implement data localization logic for Entity Framework. So that if for example a query selects Title property, behind the scenes it should reference the column Title_enGB or Title_deCH depending on the current user culture .

To achieve this, I'd like to rewrite the DbExpression CommandTrees from Entity Framework. I thought these trees are a new common .NET way for building cross database insert/update/select queries.. But now all relevant constructors/factories in the namespaces System.Data.Metadata and System.Data.Common.CommandTrees in System.Data.Entity.dll are internal!! (In msdn documentated as public, like: DbExpressionBuilder).

Does anyone have an idea to achieve this query manipulation with or without query tree rewrite?

my desired code: (public class DbProviderServicesWrapper : DbProviderServices)

/// <summary>
/// Creates a command definition object for the specified provider manifest and command tree.
/// </summary>
/// <param name="providerManifest">Provider manifest previously retrieved from the store provider.</param>
/// <param name="commandTree">Command tree for the statement.</param>
/// <returns>
/// An exectable command definition object.
/// </returns>
protected override DbCommandDefinition CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree)
{
    var originalCommandTree = commandTree as DbQueryCommandTree;
    if (originalCommandTree != null)
    {
        var expression = new MyCustomQueryRewriter(originalTree.MetadataWorkspace).Visit(originalCommandTree.Query);
        commandTree = DbQueryCommandTree.FromValidExpression(originalCommandTree.MetadataWorkspace, originalCommandTree.DataSpace, expression);
    }

    // TODO: UpdateCommand/InsertCommand

    var inner = this.Inner.CreateCommandDefinition(providerManifest, commandTree);
    var def = new DbCommandDefinitionWrapper(inner, (c, cd) => new DbCommandWrapper(c));

    return def;
}



Update

Having two title columns on one table isn't cool but its easier to implement in a first step. Later I'll join an other table with the localized fields, so the main table will only contain invariant data.

Multilanguage

Popular Answer

I agree with the answer of Shiraz that this shouldn't be what you want if you are still capable of changing the design, but I'll be assuming that this is an existing application that you are converting to Entity Framework.

If so, it matters if the Title_enGB/etc columns are mapped in the EDMX file / POCOs. If they are, I suppose this is possible. What you could do here, is use an Expression visitor that visits MemberExpressions, checks if they access a property named "Title" (you could create a whitelist of properties that needed to be treated like this) and then return a new MemberExpression that insteads accesses Title_enGB if the logged in user has that language set.

A quick example:

public class MemberVisitor : ExpressionVisitor
{
  protected override Expression VisitMember(MemberExpression node)
  {
    if(node.Member.Name == "Title")
    {
        return Expression.Property(node.Expression, "Title_" + User.LanguageCode)
    }

    return base.VisitMember(node);
  }
}

And then before you execute the query:

var visitor = new MemberVisitor();
visitor.Visit(query);

Again, this is only a good idea if you don't have any control over the database any more.

This solution may or may not be practical to you, depending on your exact situation, but rewriting queries using Expressions is definitely possible.

It's a much higher level solution than modifying how Entity Framework generates the actual SQL queries. That's indeed hidden from you, probably with good reason. Instead, you just modify the expression tree that describes the query and let Entity Framework worry about converting it to SQL.




Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why