【问题标题】:Execute expression on another IQueryable source在另一个 IQueryable 源上执行表达式
【发布时间】:2014-06-20 11:26:34
【问题描述】:

有两个类具有相同的字段结构:WebMessageWebMessageDto

我有一个可以与这两个类一起使用的 DataGrid。而且我有一个 RIA 服务,它只能提供 WebMessageDto,因为 WebMessage 具有导航属性并且它们不能被序列化。

现在,DataGrid 应该查询返回 IQueryable<WebMessageDto> 的 RIA 服务方法。我需要处理DataGrid的查询并在ORM的Table<WebMessage>上执行,然后将结果转换为WebMessageDto类型并返回给DataGrid。

我开始实现自定义 IQueryable 接口,我可以处理表达式。

public class WebMessageQueryContext
{
    // Executes the expression tree that is passed to it. 
    internal static object Execute(Expression expression, bool isEnumerable)
    {
        // DataContext.WebMessages is a ORM table which returns IQueryable<WebMessage>
        List<WebMessage> list = DataContext.WebMessages.Provider.Execute(expression);

        return WebMessageDto.ConvertFrom(list); // returning List<WebMessageDto>
    }
}

上面的代码将对这个方法进行递归调用。而且我发现了微软的示例,其中 ExpressionVisitor 中的可查询源发生了变化,现在我将原始源更改为 ORM 的表。

    protected override Expression VisitConstant(ConstantExpression c)
    {
        if (c.Type == typeof(WebMessageDtoQuerySource<WebMessageDto>))
            return Expression.Constant(DataContext.WebMessages);

        return c;
    }

执行表达式时出现异常:

Expression of type 'System.Data.Linq.Table'1[WebMessage]' cannot be used for parameter of type 'System.Linq.IQueryable'1[WebMessageDto]' of method 'Int32 Count[WebMessageDto](System.Linq.IQueryable1[WebMessageDto])'`

关于IQueryableProviders的资料不多,也不知道怎么办……谁能回答,理论上可以吗?

【问题讨论】:

  • 我可以为您提供该 LINQ 提供程序的帮助,但我不认为这是必要的。 this 在上面的代码中有什么确切的静态类型?可能不是 IQueryable 而是 IEnumerable。
  • 我使用 devExpress GridControl,它绑定到 IQueryable 集合以提供排序/过滤/分组。但是有一个限制 - GridControl 不能与实体一起使用,它只能与 dto 一起使用。
  • WebMessageDtos 方法将所有数据库行加载到内存中,进行转换,然后执行外部 linq 查询。我只需要在内存中加载必要的行并将它们作为 dto 返回。
  • @usr 我想表达式有链接到它的原始 IQueryableProvider ,其中包含上面列出的 Execute 方法。我可以将表达式的目标更改为 WebMessages 表吗?
  • 您使用的是哪个服务器模式数据源? Server Mode Concepts

标签: c# linq iqueryable


【解决方案1】:

对不起各位,我错了。在问题编辑之前,我写道 SelectWhere 之前应用于 IQueryable 导致将所有表行加载到内存中,然后执行 Where 语句。但实际上这种行为是由自定义 linq 提供程序的错误实现引起的。

当我在没有自定义 linq 提供程序的情况下使用 datagrid 时,我提到 SelectWhere 之后执行,即使 SelectWhere 之前应用也是如此。

在我的代码中:

public IQueryable<WebMessageDto> Dtos 
{ 
    get { return db.WebMessages.Select(r => new WebMessageDto { Id = r.Id });} 
}

我的 DataGrid 使用 Where/OrderBy/GroupBy 语句查询此方法,然后转换为 WebMessageDto

所以,Alex Key 的回答也是适用的。

【讨论】:

  • 很高兴 JesseJames 对它进行了排序。
【解决方案2】:

您可以使用automapper 在您的类型之间进行转换。

这是getting started guide

例如

Mapper.CreateMap<Order, OrderDto>();
OrderDto dto = Mapper.Map<OrderDto>(order);

编辑

您可以使用automapper IQueryable extensions 来提供帮助。

【讨论】:

  • 他映射没有问题。他可以轻松地完成一些任务。他想在目前正在内存中运行的数据库中运行查询。
  • 嗯,但这不只是因为它没有经过预过滤吗?可应用于 WebMessageDto 的过滤可能是 WebMessage 可用过滤的子集。那么当它是WebMessage的时候过滤然后映射到WebMessageDto呢?
  • 谢谢,但我不需要映射。我可以手动完成。我需要在映射之前而不是之后执行数据库查询。
  • @JesseJames - 您是否要恢复列的子集? IQueryable 扩展有帮助吗?
  • @AlexKey 我做了映射并使用了扩展。 return DataContext.WebMessages.Project().To&lt;WebMessageDto&gt;()。当 DataGrid 查询该方法时,它会从数据库中加载all 行,进行映射,然后应用查询条件。我需要在映射之前应用查询条件。
猜你喜欢
  • 1970-01-01
  • 2019-06-24
  • 1970-01-01
  • 2017-08-29
  • 1970-01-01
  • 2021-03-01
  • 1970-01-01
  • 2013-02-03
  • 1970-01-01
相关资源
最近更新 更多