【问题标题】:How to use the where clause with IQueryable<dynamic>如何将 where 子句与 IQueryable<dynamic> 一起使用
【发布时间】:2020-10-08 02:34:33
【问题描述】:

我正在使用带有反射的 Entity Framework Core 来动态生成一些表单。除 WHERE 子句外,一切正常。我收到以下错误:

表达式树可能不包含动态操作

我可以通过将 IQueryable 转换为 List 来解决此问题,但这会引入我想避免的不同问题。

这是我的代码:

public async void ViewCollection(PropertyInfo propertyInfo)
{
    Type propertyType = propertyInfo.PropertyType;
    InversePropertyAttribute inversePropertyAttribute = (InversePropertyAttribute)ReflectionHelpers.GetAttribute(propertyInfo, typeof(InversePropertyAttribute));


    //GET THE TYPE OF THE COLLECTION
    Type collectionType = propertyInfo.PropertyType.GenericTypeArguments[0];

    //GET THE INVERSE PROPERTY INFO
    PropertyInfo inverseProperty = collectionType.GetProperty(inversePropertyAttribute.Property);

    //GET THE FOREIGN KEY ATTRIBUTE FROM THE INVERSE PROPERTY
    ForeignKeyAttribute foreignKeyAttribute = (ForeignKeyAttribute)ReflectionHelpers.GetAttribute(inverseProperty, typeof(ForeignKeyAttribute));

    //GET THE FOREIGN KEY PROPERTY FROM THE FOREIGN KEY ATTRIBUTE
    PropertyInfo foreignKeyProperty = collectionType.GetProperty(foreignKeyAttribute.Name);

    //GET INCLUDED TYPE NAMES BY FOREIGN KEY
    IEnumerable<string> includedTypes = collectionType.GetProperties().Where(p => p.PropertyType.IsClass).Where(p => ReflectionHelpers.HasAttribute(p, typeof(ForeignKeyAttribute))).Select(r => r.Name);

    //GET THE DATA SET
    IQueryable<dynamic> items = ReflectionHelpers.GetDbCollectionByType(Db, collectionType);

    //INCLUDE THE INCLUDED TYPES BY NAME
    foreach (string includedType in includedTypes) items = items.Include(includedType);

    //THIS IS WHERE THE ERROR IS
    items = items.Where(i => foreignKeyProperty.GetValue(i, null) == PrimaryKeyProperty.GetValue(Item, null));

    await ShowCollection(collectionType, items, propertyInfo.Name);
}

如何在不将类型更改为列表的情况下解决此问题?

【问题讨论】:

    标签: c# sql dynamic reflection entity-framework-core


    【解决方案1】:

    你不能。 IQueryable 是语言集成查询 (LINQ) 的一部分 - 它是静态类型的,因此您不能使用值类型。

    IQueryable 在后台是一个表达式树,表示尚未执行的查询。表达式树部分代表查询。静态类型表示查询操作的数据。

    您最好的选择是使用expression tree API 手动构建表达式树。

    【讨论】:

      【解决方案2】:

      您不能在 dynamic 上构建查询,因为表达式树本身不支持它。相反,您应该将您的工作基于非通用IQueryable 或通用IQueryable&lt;object&gt;。例如如果ReflectionHelpers.GetDbCollectionByType 动态调用DbContext.Set&lt;T&gt;(类似于这里的Dynamically access table in EF Core 2.0),您应该能够将其转换为IQueryable&lt;object&gt;

      var items = (IQueryable<object>)ReflectionHelpers.GetDbCollectionByType(Db, collectionType);
      

      要添加Where 子句,您不应在谓词表达式中使用反射调用,而应使用Expression 类方法(来自System.Linq.Expressions 命名空间)动态构建它。像这样的:

      // (object i) => (({collectionType})i).{ForeignKey} == Item.{PrimaryKey}
      var parameter = Expression.Parameter(typeof(object), "i");
      var body = Expression.Equal(
          Expression.Property(Expression.Convert(parameter, collectionType), foreignKeyProperty),
          Expression.Property(Expression.Constant(Item), PrimaryKeyProperty));
      var predicate = Expression.Lambda<Func<object, bool>>(body, parameter);
      

      然后

      items = items.Where(predicate); // still IQueryable<object>
      

      【讨论】:

      • 伊万感谢您的努力。在尝试您的建议时,我收到此错误:错误 CS1929 'IQueryable' does not contain a definition for 'Where' 和最佳扩展方法重载 'ParallelEnumerable.Where(ParallelQuery, Func)' 需要类型为 'ParallelQuery' 的接收器
      • Ivan,这是我的 GetDbCollectionByType 代码:(IQueryable)db.GetType().GetMethod("Set").MakeGenericMethod(propertyType).Invoke(db, null);跨度>
      • IQueryable&lt;dynamic&gt; 更改为IQueryable&lt;object&gt;。这是我在测试中使用的 var items = (IQueryable&lt;object&gt;)typeof(DbContext).GetMethod("Set").MakeGenericMethod(collectionType).Invoke(db, null); 并且有效。
      • imgur.com/a/Wqk69c2 如果你想看图片
      • 嗯,有趣的是,你有Include,但没有Where。很奇怪。当您键入items.Where 时,Intellisense 会显示什么?您应该看到 4 个重载 - IEnumerable&lt;object&gt; 有 2 个,IQueryable&lt;object&gt; 有 2 个。
      猜你喜欢
      • 2014-03-20
      • 1970-01-01
      • 1970-01-01
      • 2016-05-06
      • 2015-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-20
      相关资源
      最近更新 更多