EF 代码优先 - IQueryable 具有特定小数的乘法 属性

EF code-first - IQueryable having multiplication on a specific decimal property

我一直在努力解决 Entity Framework 代码优先的以下问题。

我有一个带小数的实体 class,我有一个乘数小数参数。

我想构建一个查询(但不是调用它),其中 returns 个实体,但是 Bar 属性 需要与我的参数相乘。

编码方面:

public class Foo
{
    public Guid Id { get; set; }
    public Decimal Bar { get; set; }
}

// this simple stuff returns the entities after some filterings.
Context.Set<Foo>().Where(x => querying on many props).ToList();

这个方法和我想达到的效果类似:

public IQueryable<Foo> GetFooQuery( .. Many properties used to the query .. , Decimal Multiplier)
{
    var IQueryablePart = Context.Set<Foo>().Where(querying with the parameters);

    /* ... and what to do here? ... */
    /* IQueryablePart = IQueryablePart.Select(x => new {
           Bar = Bar * Multiplier <-- this is okay
       }); */
    // but how to retrieve the other columns without listing them one by one, and how to return the data as IQueryable<Foo> ?

    return IQueryablePart;
}

我想按以下方式使用此方法:

IQueryable<Foo> FullQuery = null;   

for(some loop, may be 10 or 1000 iterations, it depends) {
    var Part = GetFooQuery(/* .. query params ..*/, 2);

    if(MyFullQuery == null) 
        FullQuery = Part;
    else 
        FullQuery.Union(Part);
}

// and in the end, do the db call once: 
var Result = FullQuery.ToList();

在SQL中,我会这样处理:

SELECT 
    Id,
    Bar * @MyValue as Bar, 
    # and all other columns
FROM 
    Foo 
WHERE 
    (param queries 1) OR 
    (param queries 2) OR
    ---
    (param queries N)

我的问题是:通过 IQueryable 和 EF 执行此操作的方法是什么?最重要的是,我只需要调用一次数据库。

我想这可能是一些查询构建的东西,但我还不熟悉它,任何帮助将不胜感激。

EF6 不支持投影 (select) 到映射为实体的 class。因此,您唯一的选择是投射到一些匿名或特殊的 class。对于您的场景,我看到的最简单的是 class 这样的:

public class FooBar
{
    public Foo Foo { get; set; }
    public decimal Bar { get; set; }
}

那么单条查询方式可以是这样的:

public IQueryable<FooBar> GetFooQuery( .. Many properties used to the query .. , decimal multiplier)
{
    return Context.Set<Foo>()
        .Where(querying with the parameters)
        .Select(foo => new FooBar
        {
            Foo = foo,
            Bar = foo.Bar * multiplier
        });
}

现在您可以构建完整的查询:

IQueryable<FooBar> fullQuery = null;

for (some loop, may be 10 or 1000 iterations, it depends)
{
    var subQuery = GetFooQuery(/* .. query params ..*/, 2);

    fullQuery = fullQuery == null ? subquery : fullQuery.Union(subQuery);
}

注意,如果你使用不同的乘法器(否则整个过程没有意义),你最好使用LINQ Concat方法(转换为SQL UNION ALL)而不是 Union(转换为 SQL UNION)。

最后,您可以通过执行单个最终 SQL 查询将结果具体化为 Foo 序列,切换到 LINQ to Objects 并将 FooBar 转换为 Foo像这样:

var result = fullQuery.
    .AsEnumerable() // db query ends here
    .Select(fooBar =>
    {
        fooBar.Foo.Bar = fooBar.Bar;
        return fooBar.Foo;
    })
    .ToList();