将 IQueryable<X> 转换为 IQueryable<Y> 以获得更好的性能

Cast IQueryable<X> to IQueryable<Y> with better performance

我有 2 个不同的实体,Entity1Entity2,它们具有完全相同的属性。它们是从数据库的不同视图自动生成的,每个视图都有自己的实体类型。

我通过以下方式查询这些实体:

protected generatedRepository<Entity1Type> _myRepository1;
_myRepository1.GetQueryable();

protected generatedRepository<Entity2Type> _myRepository2;
_myRepository2.GetQueryable();

我正在使用 OData 创建一个 API 端点,我必须 return IQueryable<...> 才能让用户将 OData 过滤器应用于其请求

当我想 return 来自 Entity1 的实体时,我只需要写:

public IQueryable<Entity1Type> Get()
{
    return _myRepository.GetQueryable();
}

并且可以从 /api/ControllerName?$ODataFilter=...

访问这个新端点

但是,我想return有条件地从_myRepository1_myRepository2使用相同的端点

获取数据]

如果我使用相同的签名,Entity2Type 必须转换为 Entity1Type 才能 returned

我试过了

return _myRepository2.GetQueryable().Cast<Entity1Type>();  

但是失败了:

Unable to cast the type 'MyEntities2' to type 'MyEntities1'. LINQ to Entities only supports casting EDM primitive or enumeration types.

我也试过了:

return _myRepository2.GetQueryable().ToDTO<Entity2, Entity1>();

它有效,但视图有超过 100 万行并且它加载所有行,这是不可接受的

ToDto<> 方法来自:

我也尝试关注@DavidG 评论:

Mapper.CreateMap<Entity2Type, Entity1Type>

return _myRepository2.GetQueryable().ProjectTo<Entity1>();

但失败并出现此错误:

The entity or complex type 'Entity1Type' cannot be constructed in a LINQ to Entities query."

如何只创建一个端点,return从 _myRepository1_myRepository2 中以良好的性能获取可查询数据?

您可以尝试使用与您的 2 个实体相匹配的通用 DTO 并编写正确的投影。

return _myRepository2.GetQueryable().Select(e2 => 'write your projection from e2 to dto')

实体 1 也一样:

return _myRepository1.GetQueryable().Select(e1 => 'write your projection from e1 to dto')

还有关于 ToDTO

我终于找到了解决方案,但我不确定它是否是最优雅的:

我把我的 Mapper.Map<> 改成了这样:

public IQueryable<Entity2> Get(ODataQueryOptions opts)
{
    Mapper.CreateMap<Entity2Type, Entity2Type>() //Yes, Entity2 to Entity2, no typo
        .ForMember(d => d.Prop1, option => option.MapFrom(src => someCondition ? src.Prop1 : src.Prop2))
        .ForMember(d => d.Prop3, option => option.MapFrom(src => someCondition ? src.Prop3 : src.Prop4))
        .IgnoreAllNonExisting();

    var query = opts.ApplyTo(_myRepository2.GetQueryable()) as IQueryable<Entity2>;
    var results = Mapper.Map<IList<Entity2>>(query.ToList());

    return results.AsQueryable();
}

它 returns 一个 IQueryable<EntityB>,所以我的用户可以使用 OData 过滤器。由于 ApplyTo<>(因此在执行请求之前),它们被应用,这避免了将整个 table 加载到内存中,但只加载 returns 获取的结果。