【问题标题】:Linq to sql expression tree execution zone issueLinq to sql 表达式树执行区问题
【发布时间】:2023-03-09 02:14:01
【问题描述】:

我有一点问题,想知道是否有办法让我的蛋糕吃掉。

目前我有一个关于如何使用 Linq2Sql 的存储库和查询样式模式,但是我遇到了一个问题,我看不到解决它的好方法。这是一个问题的例子:

var someDataMapper = new SomeDataMapper();
var someDataQuery = new GetSomeDataQuery();
var results = SomeRepository.HybridQuery(someDataQuery)
                            .Where(x => x.SomeColumn == 1 || x.SomeColumn == 2)
                            .OrderByDescending(x => x.SomeOtherColumn)
                            .Select(x => someDataMapper.Map(x));

return results.Where(x => x.SomeMappedColumn == "SomeType");

这里要注意的主要位是 Mapper、Query、Repository 和最后的 where 子句。我这样做是作为更大重构的一部分,我们发现有很多类似的查询得到稍微不同的结果集,然后以相同的方式将它们映射到特定领域的模型。因此,例如取回 tbl_car,然后将其映射到 Car 对象。因此,映射器基本上采用一种类型并吐出另一种类型,因此与选择中通常发生的情况完全相同:

// Non mapped version
select(x => new Car 
{
    Id = x.Id,
    Name = x.Name,
    Owner = x.FirstName + x.Surname
});

// Mapped version
select(x => carMapper.Map(x));

因此,汽车映射器在执行类似查询并返回相同最终结果但沿途执行不同位的所有区域上更可重用。但是,我不断收到错误消息,说 Map 无法转换为 SQL,这很好,因为我不希望它是这样,但是我知道,因为它在表达式树中,它会尝试转换它。

{"Method 'SomeData Map(SomeTable)' has no supported translation to SQL."}

最后,返回和映射的对象被进一步向上传递到堆栈以供其他对象使用,这些对象利用 Linq to SQL 的组合能力向查询添加额外的条件,然后最终 ToList() 或迭代返回的数据,但是它们根据映射模型进行过滤,而不是原始表模型,我认为这在上一个问题中得到了很好的回答:

Linq2Sql point of retrieving data

所以总结一下,我可以使用我的映射模式而不尝试将单个部分转换为 SQL 吗?

【问题讨论】:

    标签: c# sql linq linq-to-sql expression-trees


    【解决方案1】:

    是的,你可以。将AsEnumerable() 放在最后一个Select 之前:

    var results = SomeRepository.HybridQuery(someDataQuery)
                                .Where(x => x.SomeColumn == 1 || x.SomeColumn == 2)
                                .OrderByDescending(x => x.SomeOtherColumn)
                                .AsEnumerable()
                                .Select(x => someDataMapper.Map(x));
    

    但是请注意,第二个Where - 在SomeMappedColumn 上运行的那个 - 现在将在内存中执行,而不是由数据库执行。如果最后一个 where 子句显着减少了结果集,这可能是个问题。


    另一种方法是创建一个返回该映射的表达式树的方法。只要映射中发生的所有事情都可以转换为 SQL,就应该像下面这样工作。

    Expression<Func<EntityType, Car>> GetCarMappingExpression()
    {
        return new Expression<Func<EntityType, Car>>(x => new Car 
        {
            Id = x.Id,
            Name = x.Name,
            Owner = x.FirstName + x.Surname
        });
    }
    

    用法如下:

    var results = SomeRepository.HybridQuery(someDataQuery)
                                .Where(x => x.SomeColumn == 1 || x.SomeColumn == 2)
                                .OrderByDescending(x => x.SomeOtherColumn)
                                .Select(GetCarMappingExpression());
    

    【讨论】:

    • 是的,不幸的是,一些基本查询可能会拉回数千条记录,然后在不同的服务中以不同的方式进一步过滤,因此在实际评估时它们可能会从 10000 条减少到只有 20 条。因此,如果可能的话,我不想提早取回数据。
    • 已经用表达式树路由了,谢谢你的例子!
    猜你喜欢
    • 1970-01-01
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多