本质上说,ESQL(及SQL)是表达式,那么程序是怎么表达它的语义的呢?ExpressionTrees。在EF中,它叫CommandTrees,在System.Data.Common.CommandTrees名称空间中。如同System.Linq.Expressions,了解CommandTrees是件有意义的事,也许还能做出神奇的事情。比如下面的CSDL:

<!--m.csdl-->
<Schema Namespace="N" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
  <Function Name="FuncA">
    <Parameter Name="a" Type="Int32" />
    <ReturnType Type="Int32" />
    <DefiningExpression>
      1 + a * min({2,3,4})
    </DefiningExpression>
  </Function>
  <Function Name="FuncB">
    <ReturnType>
      <CollectionType>
        <RowType>
          <Property Name="P1" Type="String"/>
          <Property Name="P2" Type="Int32"/>
        </RowType>
      </CollectionType>
    </ReturnType>
    <DefiningExpression>
      select e.P1, max(e.P2) as P2 from C.E1Set as e where e.P3 > datetime'2011-01-01 0:0' group by e.P1 having max(e.P2) > 100 order by e.P1
    </DefiningExpression>
  </Function>
  <EntityType Name="E1">
    <Key>
      <PropertyRef Name="Id" />
    </Key>
    <Property Name="Id" Type="Int32" Nullable="false" />
    <Property Name="P1" Type="String" Nullable="false" />
    <Property Name="P2" Type="Int32" Nullable="false" />
    <Property Name="P3" Type="DateTime" Nullable="false" />
  </EntityType>
  <EntityContainer Name="C">
    <EntitySet Name="E1Set" EntityType="N.E1" />
  </EntityContainer>
</Schema>

如何得到FuncA、FuncB的ESQL的CommandTress?我写了段程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Data.Metadata.Edm;
using System.Data.Common.CommandTrees;

static class InspectingCommandTrees
{
    static DbLambda CompileFuncion(EdmFunction edmFunction, MetadataWorkspace edmWorkspace)
    {
        var modelPerspectiveType = Type.GetType("System.Data.Metadata.Edm.ModelPerspective, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
        var modelPerspectiveConstructor = modelPerspectiveType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(MetadataWorkspace) }, null);
        var modelPerspective = modelPerspectiveConstructor.Invoke(new object[] { edmWorkspace });
        var parserOptionsType = Type.GetType("System.Data.Common.EntitySql.ParserOptions, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
        var parserOptionsConstructor = parserOptionsType.GetConstructor(new Type[0]);
        var parserOptions = parserOptionsConstructor.Invoke(null);
        var cqlQueryType = Type.GetType("System.Data.Common.EntitySql.CqlQuery, System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
        var compileQueryCommandLambdaMethod = cqlQueryType.GetMethod("CompileQueryCommandLambda", BindingFlags.NonPublic | BindingFlags.Static);
        var dbVariableReferenceExpressionConstructor = typeof(DbVariableReferenceExpression).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(TypeUsage), typeof(string) }, null);
        var dbVariableReferenceExpressions = edmFunction.Parameters.Select(i => (DbVariableReferenceExpression)dbVariableReferenceExpressionConstructor.Invoke(new object[] { i.TypeUsage, i.Name }));
        return (DbLambda)compileQueryCommandLambdaMethod.Invoke(null, new object[] { edmFunction.CommandTextAttribute, modelPerspective, parserOptions, new DbParameterReferenceExpression[0], dbVariableReferenceExpressions });
    }
    static string PrintExpressionTree(DbExpression edmExpression)
    {
        var printMethod = typeof(DbExpression).GetMethod("Print", BindingFlags.NonPublic | BindingFlags.Instance);
        return (string)printMethod.Invoke(edmExpression, null);
    }
    static void Main(string[] args)
    {
        try
        {
            var edmWorkspace = new MetadataWorkspace(new[] { "m.csdl" }, new Assembly[0]);
            foreach (var edmFunction in edmWorkspace.GetItems<EdmFunction>(DataSpace.CSpace).Where(i => i.NamespaceName != "Edm"))
            {
                Console.WriteLine("=====function {0}=====", edmFunction.Name);
                var edmLambda = CompileFuncion(edmFunction, edmWorkspace);
                Console.WriteLine(PrintExpressionTree(edmLambda.Body));
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    }
}

  

CommandTrees的打印结果如下:

=====function FuncA=====

|_1
|_+
|_
  |_Var(a)
  |_*
  |_Edm.Min(Collection{Edm.Int32} collection)
    |_Arguments
      |_collection
        |_NewInstance : Collection{Edm.Int32}
          |_2
          |_3
          |_4
=====function FuncB=====
Project
|_Input : '_##sort9'
| |_Sort
|   |_Input : '_##having8'
|   | |_Filter
|   |   |_Input : '_##group7'
|   |   | |_GroupBy
|   |   |   |_Input : '_##geb1', '_##group2'
|   |   |   | |_Filter
|   |   |   |   |_Input : 'e'
|   |   |   |   | |_Scan : C.E1Set
|   |   |   |   |_Predicate
|   |   |   |     |_
|   |   |   |       |_Var(e).P3
|   |   |   |       |_>
|   |   |   |       |_2011/1/1 0:00:00
|   |   |   |_Keys
|   |   |   | |_Key : 'P1'
|   |   |   |   |_Var(_##geb1).P1
|   |   |   |_Aggregates
|   |   |     |_Aggregate : '_##groupAggMax5'
|   |   |     | |_Edm.Max(Collection{Edm.Int32} collection)
|   |   |     |   |_Arguments
|   |   |     |     |_collection
|   |   |     |       |_Var(_##group2).P2
|   |   |     |_Aggregate : '_##groupAggMax6'
|   |   |       |_Edm.Max(Collection{Edm.Int32} collection)
|   |   |         |_Arguments
|   |   |           |_collection
|   |   |             |_Var(_##group2).P2
|   |   |_Predicate
|   |     |_
|   |       |_Var(_##group7)._##groupAggMax5
|   |       |_>
|   |       |_100
|   |_SortOrder
|     |_Asc
|       |_Var(_##having8).P1
|_Projection
  |_NewInstance : Record['P1'=Edm.String, 'P2'=Edm.Int32]
    |_Column : 'P1'
    | |_Var(_##sort9).P1
    |_Column : 'P2'
      |_Var(_##sort9)._##groupAggMax6

慢慢研究吧^_^

posted on 2011-07-28 15:59  zzfff  阅读(1085)  评论(0编辑  收藏  举报