首页 文章

为什么使用反射来查询DBSet会生成包含所有列的查询?

提问于
浏览
0

当我使用匿名类型从实体中选择属性时,生成的SQL是高效的,并且只包括在匿名类型中查询的列 .

例如:

dbContext.ExampleEntities.Select(obj => new {
    obj.Id
});

生成以下SQL:

SELECT 
[Extent1].[ExampleEntity_Id] AS [ExampleEntity_Id]
FROM [dbo].[ExampleEntity] AS [Extent1]
GO

但是,如果我使用反射在多个DBS上执行类似的操作,则生成的SQL包含未作为匿名类型的一部分查询的实体的属性 .

在我的用例中,我试图查询位于我的所有实体类派生自的基类中的属性 .

例如:

public class EntityBase {
    public virtual int Id { get; set; }
}

我正在查询包含派生自 EntityBase 的实体的DBSets,如下所示:

dbContext.GetType().GetProperties()
.Where(p => p.PropertyType.IsGenericType)
.Where(p => p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
.Where(p => p.PropertyType.GetGenericArguments().First().IsSubclassOf(typeof(EntityBase)))
.SelectMany(p => (IEnumerable<EntityBase>)p.GetValue(dbContext, null))
.Select(obj => new { obj.Id });

但是,为从 EntityBase 派生的每个实体生成单独的查询,并且SQL包括匿名类型中未使用的列:

SELECT 
[Extent1].[DerivedEntity_Id] AS [DerivedEntity_Id], 
[Extent1].[DerivedEntityPropertyOne] AS [DerivedEntityPropertyOne], 
[Extent1].[DerivedEntityPropertyTwo] AS [DerivedEntityPropertyTwo],
... 
FROM [dbo].[DerivedEntity] AS [Extent1]
GO

如何避免将包含从 EntityBase 派生的实体的每个DBSet的每列拉入内存?

Edit

我在下面尝试了@Pawel的建议,并将演员阵容改为IQueryable,但这没有任何效果 .

1 回答

  • 0

    通过将查询转换为以下格式,我能够实现我所需要的:

    dbContext.GetType().GetProperties()
                                 .Where(p => p.PropertyType.IsGenericType)
                                 .Where(p => p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
                                 .Select(p => p.PropertyType.GetGenericArguments().First())
                                 .Where(t => t.IsSubclassOf(typeof(EntityBase)))
                                 .Select(t => ((IQueryable<EntityBase>)dbContext.Set(t)).Select(obj => obj.Id))
                                 .SelectMany(obj => obj)
                                 .Dump();
    

    它的可读性稍差,因为最后 Where 之后的 Select 必须嵌套,但它可以工作 .

    我无法让linq提供程序生成一个SQL语句,它是所有 DBSet 中的单个联合,但这足以满足我的需要 .

相关问题