英文:
Why does EF throw an error with LastOrDefault in Include operations but not with OrderByDescending?
问题
我需要从Monitoring表中获取最后一条记录。
return await _context.Applications
.Include(s => s.Elements)
.ThenInclude(d => d.Monitoring.LastOrDefault())
.ToListAsync();
但是 EF 抛出了一个错误:
System.InvalidOperationException: 表达式 's.Elements.AsQueryable().LastOrDefault()' 在 'Include' 操作中无效,因为它不代表属性访问:'t => t.MyProperty'。
要针对派生类型上声明的导航属性,请使用强制转换('t => ((Derived)t).MyProperty')或 'as' 运算符('t => (t as Derived).MyProperty')。
集合导航访问可以通过组合 Where、OrderBy(Descending)、ThenBy(Descending)、Skip 或 Take 操作进行过滤。
但是,当我使用OrderByDescending执行相同的请求时,它可以正常工作。
return await _context.Applications
.Include(s => s.Elements)
.ThenInclude(d => d.Monitoring.OrderByDescending(c => c.Id))
.ToListAsync();
有人能解释一下使用OrderByDescending和LastOrDefault之间的区别吗?
在这种情况下,如何正确获取最后一项?
英文:
I need to get the last record from the Monitoring table
return await _context.Applications
.Include(s => s.Elements)
.ThenInclude(d => d.Monitoring.LastOrDefault())
.ToListAsync();
But EF throw an error :
System.InvalidOperationException: The expression 's.Elements.AsQueryable().LastOrDefault()' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'.
To target navigations declared on derived types, use casting ('t => ((Derived)t).MyProperty') or the 'as' operator ('t => (t as Derived).MyProperty').
Collection navigation access can be filtered by composing Where, OrderBy(Descending), ThenBy(Descending), Skip or Take operations.
But when I execute the same request with OrderByDescending it works fine.
return await _context.Applications
.Include(s => s.Elements)
.ThenInclude(d => d.Monitoring.OrderByDescending(c => c.Id))
.ToListAsync();
Can anyone explain what is the difference between using OrderByDescending and LastOrDefault?
How would it be correct to get the last item in this case?
答案1
得分: 2
以下是您要翻译的内容:
区别在于对其中一个的支持已经实现,而对另一个则没有。这在 EF Core 文档中有记录,关于Filtered Include的部分:
> 支持的操作包括:Where
、OrderBy
、OrderByDescending
、ThenBy
、ThenByDescending
、Skip
和 Take
。
因此,您可以执行以下操作:
return await _context.Applications
.Include(s => s.Elements)
.ThenInclude(d => d.Monitoring.OrderByDescending(c => c.Id).Take(1))
.ToListAsync();
这将导致 Monitoring
最多只有一个具有最大 Id
的元素。
英文:
The difference is that support for one is implemented and for another - is not. This is documented in the EF Core docs for Filtered Include:
> Supported operations are: Where
, OrderBy
, OrderByDescending
, ThenBy
, ThenByDescending
, Skip
, and Take
.
So you can do:
return await _context.Applications
.Include(s => s.Elements)
.ThenInclude(d => d.Monitoring.OrderByDescending(c => c.Id).Take(1))
.ToListAsync();
Which should result in Monitoring
having at most one element with largest Id
.
答案2
得分: 0
以下是您要翻译的内容:
异常描述了您的问题几乎完美。
Include
或 ThenInclude
无法接受一个 object
,这是 LastOrDefault()
的结果。
当您调用 OrderByDescending
时,它仍然是一个属性访问器,可以被 EF 转换为 SQL 代码 - 同时,它是集合的指针。
尝试将您的代码直接转换为 SQL 代码,您如何执行 "JOIN" 操作与单行(这就是 LastOrDefault
尝试执行的操作)? - 你不能。
LastOrDefault
和 OrderByDescending
之间的区别在于,第一个结果是一个记录,而另一个结果是一个按您的喜好排序的集合。
英文:
The exception describes your problem almost perfectly.
Include
or ThenInclude
can't accept an object
, which is a result of LastOrDefault()
.
When you you call OrderByDescending
instead, it's still a property accessor which can be converted by EF to the SQL code - also, it's a pointer to the collection.
Try to convert your code directly to the SQL code, how can you perform "JOIN" with a single row (this is what LastOrDefault
tries to perform) ? - you can't.
The difference between LastOrDefault
and OrderByDescending
is that first one, results in a single record, and another one results in a collection, ordered by your preference.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论