2010-11-27 4 views
1

J'ai besoin d'un moyen de parcourir une arborescence d'expression LINQ-to-SQL pour extraire le (s) nom (s) de la table dans la requête. Même la première table utilisée dans la requête suffirait probablement.C# Traverse l'arborescence d'expression pour extraire les noms de tables

Exemple:

var query = from c in Db.Customers select c; 

Et la fonction idéale:

string TableName = ExtractTablesFromQuery(query); 

reviendriez chaîne "Les clients"

Répondre

4

LINQ to SQL ne pas exposer cette fonctionnalité pour vous si vous avez deux options

Utilisez la fonction et analyser le TSQL

dataContext.GetCommand (myQuery) Cela peut être un peu délicate avec des jointures etc, mais vous obtenez les noms garantir des tables exactes qui vont être impliqués.

Visitez l'arbre d'expression vous

Ce n'est pas trop difficile, mais a le problème dans ce LINQ à infère SQL et permet d'optimiser les tables à utiliser effectivement pour que vous n'obtenir un résultat précis à 100% de qu'est-ce qui va arriver? par exemple. Si vous avez rejoint une table mais que vous n'avez renvoyé aucun des résultats, elle serait optimisée, mais vous ne le sauriez pas en visitant l'arbre d'expression à moins que vous n'optimisiez exactement comme LINQ to SQL (ce qui serait beaucoup de travail).

Si vous voulez essayer # 2 de toute façon est ici un exemple pour vous aider à démarrer:

public static class TableFinder 
{ 
    public static IEnumerable<string> GetTableNames(this DataContext context, IQueryable queryable) { 
     var visitor = new TableFindingVisitor(context.Mapping); 
     visitor.Visit(queryable.Expression); 
     return visitor.Tables.Select(t => t.TableName).Distinct().AsEnumerable(); 
    } 

    class TableFindingVisitor : ExpressionVisitor 
    { 
     private readonly HashSet<MetaTable> foundTables = new HashSet<MetaTable>(); 
     private readonly MetaModel mapping; 

     public TableFindingVisitor(MetaModel mapping) { 
      this.mapping = mapping; 
     } 

     public override Expression Visit(Expression node) { 
      return base.Visit(node); 
     } 

     protected override Expression VisitConstant(ConstantExpression node) { 
      if (node.Type.GetGenericTypeDefinition() == typeof(Table<>)) 
       CheckType(node.Type.GetGenericArguments()[0]); 
      return base.VisitConstant(node); 
     } 

     protected override Expression VisitMember(MemberExpression node) { 
      CheckType(node.Member.DeclaringType); 
      return base.VisitMember(node); 
     } 

     public IEnumerable<MetaTable> Tables { get { return foundTables; } } 

     private void CheckType(Type t) { 
      var table = mapping.GetTable(t); 
      if (table != null && !foundTables.Contains(table)) 
       foundTables.Add(table); 
     } 
    } 

Pour utiliser ce que vous foreach sur les résultats de dataContext.GetTables (myQuery);

+0

Je suis honoré d'avoir |) répondu à ma question! Je ne l'ai pas encore testé, mais ce que vous avez proposé ici semble exactement correct et je vais donc le marquer comme la réponse. Je vous remercie!! – msigman

+0

Pourquoi visiter les constantes? Sont-ils toujours des tables? – HelloWorld

Questions connexes