我的查询看起来有点像这样:
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());
当然不是那样,但你希望得到这个想法。
答案 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。