我有一个看起来像这样的查询:
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的过滤值。