如何在IQueryExpressionInterceptor中查找实体类型?

问题描述 投票:0回答:1

如何找到传递给

Expression
IQueryExpressionInterceptor.QueryCompilationStarting
引用的所有实体类型?我应该在表达式树的哪里寻找它们?

我尝试了各种查询并检查了调试器中的

Expression
。查询中涉及的实体类型似乎总是出现在表达式及其递归
Type
Arguments
属性中,作为其本身或作为
IQueryable
IIncludableQueryable
的类型参数。但我想知道是否有方法可以构造一个 EF 查询,但事实并非如此。

以下是我测试过的一些查询形状。在每种情况下,我都会看到一系列嵌套的

MethodCallExpression
(LINQ 类型)包围着
EntityQueryRootExpression
(EF 类型)。

var first = await db.Foos.FirstAsync();

var name = await db.Foos.Select(f => f.Name).FirstAsync();

var foosWithBars = await db.Foos.Include(f => f.Bars).ToListAsync();

var bars = await db.Foos
    .Where(f => f.FooId == 1)
    .SelectMany(f => f.Bars)
    .ToListAsync();

var firstBar = await db.Foos
    .OrderBy(f => f.FooId)
    .Select(f => f.Bars.First())
    .FirstAsync();

entity-framework-core expression interceptor linq-expressions
1个回答
1
投票

考虑仅关注

QueryRootExpression
MemberExpression
,因为它们包含有关 LINQ 查询涉及哪些实体的足够信息。

下面是一个简单的

ExpressionVisitor
实现,它收集了这些实体类型:

用途:

var visitor = new EntitiesCollectorVisitor(db.Model);
visitor.Visit(queryExpression);

foreach (var entityType in visitor.Entities)
{
    Console.WriteLine(entityType.ClrType.Name);
}

实施:

public class EntitiesCollectorVisitor : ExpressionVisitor
{
    private readonly IModel _model;

    public HashSet<IEntityType> Entities { get; } = new();

    public EntitiesCollectorVisitor(IModel model)
    {
        _model = model;
    }

    void CollectTypes(Type type)
    {
        var entityType = _model.FindEntityType(type);
        if (entityType != null)
        {
            Entities.Add(entityType);
        }
        else if (type.IsGenericType)
        {
            foreach (var genericArg in type.GenericTypeArguments)
                CollectTypes(genericArg);
        }
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        CollectTypes(node.Type);
        return base.VisitMember(node);
    }

    protected override Expression VisitExtension(Expression node)
    {
        if (node is QueryRootExpression rootExpression)
        {
            CollectTypes(rootExpression.ElementType);
        }
        return base.VisitExtension(node);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.