问题描述
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);
我进行了一些计算,运行了一些其他代码,然后最后我想返回按名称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]
对其进行注释。 - 然后,您需要先加载项目,然后然后对它们进行排序。
- 但是,如果要在数据库服务器中执行分页或排序,则需要在查询中直接使用
EndTime
和StartTime
。
方法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);
更改您的班级
我将您的班级修改为如下形式:
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清楚应该忽略该属性。 - 请注意,该属性如何包含单位名称(“分钟”),否则,如果该属性是毫秒,秒,分钟等,则不会很明显。
- 还要注意,属性如何检查
StartTime
和EndTime
是否为空,并在这种情况下返回null
。您的代码没有,这意味着如果数据库中有NULL
个值或没有完全初始化任何Item
个对象实例,则程序将崩溃。 - 如果无法将
StartTime
和EndTime
的值 设为NULL
,则需要向数据库中添加NOT NULL
并更新EF实体类,以便属性是DateTime
而不是DateTime?
。