【问题标题】:Sort a Linq query对 Linq 查询进行排序
【发布时间】:2018-11-05 19:35:36
【问题描述】:

我正在尝试使用表中名为优先级的字段对以下 Linq 查询进行排序。

foreach (var faculty in specialty.faculty_specialties.Where(f => f.faculty.active))

我尝试在末尾添加:.OrderByDescending(p => p.priority),但没有成功。 我在 MVC 项目中使用 C# 和 Visual Studio。谢谢

【问题讨论】:

  • 现在我对你试图实现的目标感到困惑(这就是你得到很多反对票的原因)。让我们不要为此感到不安。请在您的问题中更好地解释您尝试做什么。似乎您想遍历教员对象,但 foreach 中没有循环。
  • 定义“不成功”。 发生了什么,为什么不是你想要发生的?
  • OrderByDescending 绝对可以工作。请添加有关预期结果和实际结果的一些详细信息。
  • 感谢你们的 cmets 并帮助我更好地澄清我的问题。我正在遍历教职员工(活跃的),并尝试使用一个名为“优先级”的字段来排序结果。现在它显示教职员工并按 id 排序。看起来我写错了... foreach (var Faculty in special.faculty_specialties.Where(f => f.faculty.active).OrderByDescending(p => p.faculty.priority))

标签: c# entity-framework linq


【解决方案1】:

首先将您的逻辑分解为单独的操作,而不是尝试将所有内容写在一行中。编译器是智能 cookie,因此它们可以很好地优化事物,没有必要让您的代码更难阅读/理解:

var facultySpecialties = specialty.faculty_specialties
  .Where(fs => fs.faculty.active)
  .ToList(); // Executes the query to retrieve faculty specialties.

foreach(var facultySpecialty in facultySpecialties)
{
  // do stuff.
}

请注意您在查询中引用的实体的范围。上面的查询将返回faculty_specialties,而不是faculties。需要注意的一个问题:由于这会返回 fac_specs,如果您想在 foreach 循环中访问 fac_spec 和教员的详细信息,那么也包括教员。

var facultySpecialties = specialty.faculty_specialties
  .Include(fs => fs.faculty)
  .Where(fs => fs.faculty.active)
  .ToList(); 

如果您只想要院系,而不需要来自 fac_spec 的信息:

var faculties = specialty.faculty_specialties
  .Select(fs => fs.faculty)
  .Where(f => f.active)
  .ToList();

这会从我们的 fac_specs 中选择教员。请注意 Where 子句发生了变化,因为 .Select() 之后的范围变为 Faculties 而不是 Faculty_Specialities。如果您仍需要 fac_specs 中的详细信息,可以使用 .Include(f => f.faculty_specialties),但如果不需要它们,请不要包含关系,因为这会增加查询的性能成本和传输成本(大小)。

现在您想要订购学院。问题是优先权适用于哪个实体?如果 Priority 是 Faculty 中的一个字段,则:

var faculties = specialty.faculty_specialties
  .Select(fs => fs.faculty)
  .Where(f => f.active)
  .OrderBy(f => f.Priority)
  .ToList();

但是,我怀疑优先考虑的是系专业。

如果您有从学院返回到学院专业的导航属性(我假设是多对多关系,因此学院可以映射 ICollection<faculty_specialities>)并且学院在您的上下文中是一个 DbSet,您可能想要重组查询,因为这将使订购更容易:

var faculties = dbContext.Faculties
  .Where(f => f.active && f.faculty_specialties.Any(fs => fs.specialty.specialtyId == specialty.specialtyId))
  .ToList();

在faculty_speciality.priority上执行命令:

var faculties = dbContext.Faculties
  .Where(f => f.active 
    && f.faculty_specialties.Any(fs => fs.specialty.specialtyId == specialty.specialtyId))
  .OrderByDescending(f => f.faculty_specialties.Min(fs => fs.priority))
  .ToList();

您可以尝试对原始查询进行排序,例如:

var faculties = specialty.faculty_specialties
  .OrderBy(fs => fs.priority)
  .Select(fs => fs.faculty)
  .Where(f => f.active)
  .ToList();

但是我不确定这种排序是否会在最终结果集中得到体现。

对此类查询要考虑的最后一件事是,随着系统的增长,数据量可能会使此类操作变得非常昂贵,因为给定专业的设施数量会增加。您应该在使用 .Take().Skip() 的早期考虑对结果大小和分页支持施加限制,除非系统大小的上限被限制在一个合理的数字上。

【讨论】:

  • 感谢您的精彩解释并帮助我思考如何推理解决方案。我现在开始工作了。
  • 您为什么更喜欢使用ToList 而不是让foreach 创建对象而无需创建List 的开销?
  • 从内存的角度来看没有区别。如果没有.ToList(),您将拥有一个IQueryable<T>,它将在首次访问时执行和加载。 (第一次迭代)调用.ToList() 仅标记执行点。 执行点之后的任何 Linq 操作都将是 Linq2Object 而不是 Linq2EF。因此,例如,如果您想通过进一步的 Linq 缩减来调用私有方法、扩展方法或未映射的属性,这些可以在 ToList() 之后安全地完成。这也为您提供了一个调试点,您可以在其中检查结果。
猜你喜欢
  • 2016-10-27
  • 1970-01-01
  • 2022-12-01
  • 1970-01-01
  • 2011-09-25
  • 2011-10-31
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多