Era*_*cht 1 .net c# linq entity-framework entity-framework-core
我需要where
多次检查相同的特定条件(子句):
return _ctx.Projects.Where(p => p.CompanyId == companyId &&
(p.Type == Enums.ProjectType.Open ||
p.Invites.Any(i => i.InviteeId == userId))).ToList()
Run Code Online (Sandbox Code Playgroud)
'&&'之后的部分将导致用户无法检索受限制的项目.
我想把这个检查抽象成一个函数.将来这些条件可能会改变,我不想替换所有LINQ查询.
我用以下扩展方法做到了这一点:
public static IQueryable<Project> IsVisibleForResearcher(this IQueryable<Project> projects, string userId)
{
return projects.Where(p => p.Type == Enums.ProjectType.Open ||
p.Invites.Any(i => i.InviteeId == userId));
}
Run Code Online (Sandbox Code Playgroud)
现在我可以将LINQ查询更改为:
return _ctx.Projects.Where(p => p.CompanyId == companyId)
.IsVisibleForResearcher(userId).ToList()
Run Code Online (Sandbox Code Playgroud)
这会生成相同的SQL查询.现在我的问题开始时我想在另一个有项目的DbSet上使用这个扩展方法.
想象一下,公司有项目.我只想检索用户至少可以看到一个项目的公司.
return _ctx.Companies
.Where(c => c.Projects.Where(p =>
p.Type == Enums.ProjectType.Open ||
p.Invites.Any(i => i.InviteeId == userId))
.Any())
Run Code Online (Sandbox Code Playgroud)
在这里我也想使用扩展方法.
return _ctx.Companies
.Where(c => c.Projects.AsQueryable().IsVisibleForCompanyAccount(userId).Any())
Run Code Online (Sandbox Code Playgroud)
这引发以下异常:
Remotion.Linq.dll中出现"System.NotSupportedException"类型的异常,但未在用户代码中处理
附加信息:无法解析表达式'c.Projects.AsQueryable()':目前不支持方法'System.Linq.Queryable.AsQueryable'的重载.
比我创建了以下扩展方法:
public static IEnumerable<Project> IsVisibleForResearcher(this ICollection<Project> projects, string userId)
{
return projects.Where(p => p.Type == Enums.ProjectType.Open ||
p.Invites.Any(i => i.InviteeId == userId));
}
Run Code Online (Sandbox Code Playgroud)
但这也不起作用.
有没有人有想法?或朝着正确的方向迈出一步.
顺便说一句,我在.NET Core上使用Entity Framework Core
更新:
使用a Expression<Func<>>
导致了同样的异常:
目前不支持'System.Linq.Queryable.AsQueryable'.
更新2
Thx @ ivan-stoev提供解决方案.我还有一个问题.我还想检索"可见"项目的数量.
我通过这样做修复它:
var companies = _ctx.Companies
.WhereAny(c => c.Projects, Project.IsProjectVisibleForResearcher(userId))
.Select(c => new CompanyListDto
{
Id = c.Id,
Name = c.Name,
LogoId = c.LogoId,
ProjectCount = _ctx.Projects.Where(p => p.CompanyId == c.Id)
.Count(Project.IsProjectVisibleForResearcher(userId))
});
Run Code Online (Sandbox Code Playgroud)
但我找不到一种方法来c.Projects
代替使用ctx.Projects.Where(p => p.CompanyId == c.Id)
生成的SQL是正确的,但我想避免这种不必要的检查.
真诚的,布莱希特
在IQueryable<T>
查询表达式中使用表达式/自定义方法一直存在问题,需要一些表达式树后处理.例如,LinqKit提供AsExpandable
,Invoke
并Expand
为此目的而定制的扩展方法.
虽然不是那么一般,但这里是一个使用第三方软件包的示例用例的解决方案.
首先,在方法中提取谓词的表达式部分.合理的地方IMO是Project
班级:
public class Project
{
// ...
public static Expression<Func<Project, bool>> IsVisibleForResearcher(string userId)
{
return p => p.Type == Enums.ProjectType.Open ||
p.Invites.Any(i => i.InviteeId == userId);
}
}
Run Code Online (Sandbox Code Playgroud)
然后,创建一个这样的自定义扩展方法:
public static class QueryableExtensions
{
public static IQueryable<T> WhereAny<T, E>(this IQueryable<T> source, Expression<Func<T, IEnumerable<E>>> elements, Expression<Func<E, bool>> predicate)
{
var body = Expression.Call(
typeof(Enumerable), "Any", new Type[] { typeof(E) },
elements.Body, predicate);
return source.Where(Expression.Lambda<Func<T, bool>>(body, elements.Parameters));
}
}
Run Code Online (Sandbox Code Playgroud)
使用此设计,不需要您当前的扩展方法,因为对于Projects
查询,您可以使用:
var projects = _ctx.Projects
.Where(p => p.CompanyId == companyId)
.Where(Project.IsVisibleForResearcher(userId));
Run Code Online (Sandbox Code Playgroud)
并为Companies
:
var companies = _ctx.Companies
.WhereAny(c => c.Projects, Project.IsVisibleForResearcher(userId));
Run Code Online (Sandbox Code Playgroud)
更新:此解决方案非常有限,因此如果您有不同的用例(特别是在Select
第二次更新中的表达式内),您最好使用某些第三方软件包.例如,这是LinqKit解决方案:
// LInqKit requires expressions to be put into variables
var projects = Linq.Expr((Company c) => c.Projects);
var projectFilter = Project.IsVisibleForResearcher(userId);
var companies = db.Companies.AsExpandable()
.Where(c => projects.Invoke(c).Any(p => projectFilter.Invoke(p)))
.Select(c => new CompanyListDto
{
Id = c.Id,
Name = c.Name,
LogoId = c.LogoId,
ProjectCount = projects.Invoke(c).Count(p => projectFilter.Invoke(p))
});
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1579 次 |
最近记录: |