动态构建实体框架选择查询

时间:2017-04-27 13:02:59

标签: c# entity-framework

我的查询看起来有点像这样:

context.Users
.........
.Select(user => new UserDTO
{
    UserName = user.Name,
    DataList = context.Data.Where(x => x.UserId == user.Id).ToList(),
    Emails = context.Email.Where(x => x.UserId == user.Id).ToList(),
    BankAccounts = context.BankAccount.Where(x => x.UserId == user.Id).ToList(),
    .....
}

这个问题就是这一切都会产生一个大规模的查询,因为所有这些子选择都是单独的列表。这些选择的唯一原因是因为有时我需要对它们进行过滤。所以我想知道是否可以动态构建它们,如下所示:

var query = context.Users
    .........
    .Select(user => new UserDTO
    {
        UserName = user.Name,
        .....
    }

if (EmailFilter) query.Select.Add(Emails, context.Email.Where(x => x.UserId == user.Id).ToList());

if (AccountsFilter) query.Select.Add(BankAccounts, context.BankAccount.Where(x => x.UserId == user.Id).ToList());

当然不是那样,但你希望得到这个想法。

3 个答案:

答案 0 :(得分:1)

您可以从DbContext外部动态构建投影。如果您查看表达式,您将注意到在调用EF方法之前如何创建选择查询。

例如我使用的是这样的:

internal class TenantFullProjector : IProjector<Tenant, TenantProjection>
{
    public Expression<Func<Tenant, TenantProjection>> GetProjection()
    {
        return (x) => new TenantProjection()
        {
            Code = x.Code,
            DatabaseId = x.DatabaseId,
            Id = x.Id,               
        };
    }
}

我有一个IProjector接口,我的存储库层使用它。重要的是它返回一个表达式,最终将租户域模型映射到TenantProjection投影模型。只要我正确实现接口,我就可以创建任意多个不同的版本。例如,此示例映射所有列,而其他投影仪可能只选择列的子集。

在存储库层中,我将执行以下操作:

return query.Select(myProjectionExpression); 

...其中query等于ctx.Set()。

你可以为where语句做同样的事情。

答案 1 :(得分:1)

如果您没有导航属性,那么我认为您可以在Where内使用此标志,如下所示:

Select(user => new UserDTO
{
    UserName = user.Name,
    DataList = context.Data.Where(x => x.UserId == user.Id).ToList(),
    Emails = context.Email.Where(x => EmailFilter && x.UserId == user.Id).ToList(),
    BankAccounts = context.BankAccount.Where(x => AccountsFilter && x.UserId == user.Id).ToList(),
    .....
}

答案 2 :(得分:0)

也许是这样的:

var query = context.Users
    .Select(user => new
    {
        UserName = user.Name,
        Emails = EmailFilter ? context.Email.Where(x => x.UserId == user.Id).ToList() : null,
        BankAccounts = AccountsFilter ? context.BankAccount.Where(x => x.UserId == user.Id).ToList() : null,
        // and so on
    });

根据过滤器值,您将获得值列表,或者在结果属性中为null。