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



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

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());

当然不是完全如此,但您希望您能得到这个主意。

如果您没有导航属性,那么我认为您可以在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(),
    .....
}

您可以从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接口。重要的是,它返回一种表达式,该表达式最终将租户域模型映射到penantprothodoction投影模型中。只要正确实现接口,我就可以创建尽可能多的不同版本。例如,实例映射所有列,而其他投影仪只能选择列的子集。

在存储库层中,我会做这样的事情:

return query.Select(myProjectionExpression); 

...查询等于ctx.set((。

您可以为您的语句做完全相同的事情。

也许是这样的东西:

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的过滤值。

最新更新