C#遍历表达式树以提取表名

时间:2010-11-27 16:43:56

标签: linq-to-sql expression-trees

我需要一种遍历LINQ-to-SQL表达式树的方法来提取查询中的表名。即使只是查询中使用的第一个表也可能就足够了。

示例:

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

理想的功能:

string TableName = ExtractTablesFromQuery(query);

会返回字符串“Customers”

1 个答案:

答案 0 :(得分:4)

LINQ to SQL不会为您公开此功能,因此您有两个选项。

使用dataContext.GetCommand(myQuery)函数并解析TSQL

对于连接等,这可能会有点棘手,但可以保证您获得将要涉及的确切表名。

自己访问表达式树

这不是太难,但是问题在于LINQ to SQL推断并优化了哪些表实际使用,因此您将无法获得100%准确的结果。例如如果你加入了一个表但没有返回任何结果,那么它会被优化掉但你不会通过访问表达式树来了解这一点,除非你完全像LINQ to SQL那样进行优化(这将是很多工作)。

如果你想尝试#2,这里就是一个让你入门的例子:

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);
        }
    }

要使用此功能,您需要预先处理dataContext.GetTables(myQuery)的结果;