【问题标题】:Is there a workaround when using linq to create a searchPredicate that exceeds 2100 parameters?使用 linq 创建超过 2100 个参数的 searchPredicate 时是否有解决方法?
【发布时间】:2019-07-16 19:27:08
【问题描述】:

基本上,我有一个报告列表,每个报告都属于一个区域。每个用户在每个区域都有权限。我需要列出我的用户可以看到的报告,即属于登录用户至少具有读取权限的区域的报告。

我正在使用 linq 表达式来创建谓词并运行 detachedQuery。

我一直在研究这个问题,发现了很多建议,例如:-LinqKit - https://www.tabsoverspaces.com/233644-playing-with-parameters-limit-on-sql-server-with-entity-framework - Entity Framework Hitting 2100 Parameter Limit

似乎不是我的情况,因为我并没有完全检索列表,我只是在运行一个谓词。

使用“包含”可以通过 2100 个参数解决这个问题,因为我的数据库中有 3000 多个区域。我首先尝试将区域划分为两个列表,第一个包括我有权限的区域,第二个包括不允许的区域。最小的列表进入我的谓词。这种方法在一段时间内工作得很好,但现在我有超过 4500 个区域。因此,这不再起作用。

var predicate = PredicateBuilder.Create<Report>();

var areasWithPermission = user.Permissions.Where(v => v.Access != AccessType.NotAllowed).Select(v => v.Area.Id).ToList();
var areasWithoutPermission= user.Permissions.Where(v => v.Access == AccessType.NotAllowed).Select(v => v.Area.Id).ToList();

var predicateSearchPermissions = PredicateBuilder.Create<Report>();

if (areasWithPermission > areasWithoutPermission) {
    predicateSearchPermissions = predicateSearchPermissions.OrElse(a => !areasWithoutPermission.Contains(a.Area.Id))
}
else
{
    predicateSearchPermissions = predicateSearchPermissions.OrElse(a => areasWithPermission .Contains(a.Area.Id))
}

predicate = predicate.AndAlso(predicateSearchPermissions);

这是我的环境的简单表示:

【问题讨论】:

  • 限制不在SQL一方,而是受Entity Framework限制。你实际上可以做一个左连接。是的,您最终会获得更多记录,但事后您始终可以通过 DistinctGroupBy
  • 您为什么使用ToList 并将数据拉到客户端?
  • @Franck 即使做左连接我仍然需要使用包含,不是吗?
  • @NetMage 我创建这两个列表只是因为我需要将最小的作为参数传递给“包含”。这对我来说过去很好用,因为如果我有例如 5000 个区域,用户通常只有 100 个区域的编辑权限。但是现在我发现一个用户对 2500 个区域有编辑权限,对 2500 个区域有只读权限的情况。这破坏了我的逻辑
  • 权限和报表是否在同一个数据库中?如果是这样,您不应该仅仅为了再次发送它们而提出许可。

标签: c# .net entity-framework linq


【解决方案1】:

不要将权限带入内存只是为了将它们发送下来。而是在查询中“加入”表。 比如:

var reports = from r in reports
              let areasWithPermission = user.Permissions.Where(v => v.Access != AccessType.NotAllowed).Select(v => v.Area.Id)
              let areasWithoutPermission = user.Permissions.Where(v => v.Access == AccessType.NotAllowed).Select(v => v.Area.Id)
              where areasWithPermission.Any(id => id == r.Area.Id) ||
                    !areasWithoutPermission.Any(id => id == r.Area.Id)
              select r;

【讨论】:

  • 由于我无法理解的原因,使用“任何”总是返回错误“不支持指定的方法。”
  • 你确定你那里没有任何 ToList 吗?
  • 是的,但是 user.Permissions 返回一个 IList,而 areasWithPermission 变成一个 IEnumerable。我正在尝试类似predicate = predicate.AndAlso(v =&gt; user.Permissions.Where(p =&gt; p.AccessType != AccessType.ReadOnly).Any(id =&gt; Id == Area.Id));
  • 所有表都需要 IQueryable 才能在 SQL 服务器上执行查询
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-07
  • 2015-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多