c# - Entity Framework Core - 对计算字段进行排序

标签 c# entity-framework linq asp.net-core .net-core

我有一个与此类似的模型:

Public class Item {
  public int Id { get; set; }
  public string Name { get; set; }
  public DateTime? StartTime { get; set; }
  public DateTime? EndTime { get; set; }
  public int? TotalTime
  {
    get
    {
      return Convert.ToInt32(EndTime.Value - StartTime.Value).TotalMinutes);
    }
  }
  etc...

然后我得到一个项目列表:

IQueryable<Items> items = itemsContext.Items.Where(e => e.Id > 0);

我做了一些计算,运行一些其他代码,然后最后我想返回按 Name ASC 和 TotalTime DESC 排序的项目列表。这是我尝试过的:

items = items.OrderBy(e => e.Name).ThenByDescending(e => e.TotalTime);

但我收到错误:“无法翻译 LINQ 表达式。要么以可翻译的形式重写查询,要么通过插入对 AsEnumerable()、AsAsyncEnumerable 的调用显式切换到客户端计算()、ToList() 或 ToListAsync()。”

我也尝试过这个,但得到同样的错误:

items = items.OrderBy(e => e.Name).ThenByDescending(e => e.TotalTime ?? 0);

如何按 TotalTime 对数据集进行排序?

最佳答案

  • 由于TotalTime不是您数据库的一部分,因此您需要使用[NotMapped]对其进行注释。
  • 然后您需要首先加载项目,然后按它们排序。
  • 但是,如果您想在数据库服务器中执行分页或排序,则需要直接在查询中使用 EndTimeStartTime

方法 1:先加载,然后在应用程序代码中排序:

List<Items> loadedItems = await itemsContext.Items
    .Where( e => e.Id > 123 )
    .ToListAsync()
    .ConfigureAwait(false); // `ConfigureAwait(false)` MAY be optional, depending on your application.

List<Items> sortedItems = loadedItems
    .OrderBy(e => e.Name)
    .ThenByDescending(e => e.TotalTime)
    .ToList(); // <-- Note this is NOT `ToListAsync` because the items are already loaded into memory.

方法 2:在 SQL 中排序:

List<Items> loadedSortedItems = await itemsContext.Items
    .Where( e => e.Id > 123 )
    .OrderBy( e => e.Name )
    .ThenByDescending( e => e.EndTime - e.StartTime )
    .ToListAsync()
    .ConfigureAwait(false);

对您的类(class)进行更改

我会将您的类(class)修改为如下所示:

public class Item {
  public int       Id        { get; set; }
  public string    Name      { get; set; }
  public DateTime? StartTime { get; set; }
  public DateTime? EndTime   { get; set; }
  
  [NotMapped]
  public int? TotalTimeMinutes
  {
    get
    {
        if( this.EndTime == null || this.StartTime == null ) return null;

        TimeSpan diff = this.EndTime.Value - this.StartTime.Value;
        return (Int32)Math.Round( diff.TotalMinutes );
    }
  }
  • NotMapped 属性向 Entity Framework 明确表明它应该忽略该属性。
  • 请注意该属性如何包含单位名称(“分钟”),否则属性是否为毫秒、秒、分钟等并不明显。
  • 另请注意该属性如何检查 StartTimeEndTime 是否为 null,并在这种情况下返回 null。您的代码没有,这意味着如果数据库中存在 NULL 值或任何 Item 对象实例未完全初始化,您的程序将会崩溃。
  • 如果 StartTimeEndTime不能NULL,那么您需要添加 NOT NULL 添加到数据库并更新 EF 实体类,以便属性为 DateTime 而不是 DateTime?

关于c# - Entity Framework Core - 对计算字段进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64435255/

相关文章:

c# - C#中的正则表达式类

javascript - Sweet Alert函数在js脚本调用时不会触发

c# - 与 c# 中的 string+=int 不一致的行为

c# - DatagridRow IsSelected 不完全工作

c# - 适用于 Visual Studio 2012/2013 的 MySQL

C# - 两个大字符串数组的模糊比较

c# - LINQ to Dictionary - 使用 XML

entity-framework - 使用 Entity Framework 进行反规范化

c# - 如何提高EF中查询的执行速度

c# - 为什么我的模拟列表没有删除某个元素?