我有一个MS SQL数据库,其中包含这些表Item { ItemId | SerialNumber | Type | Height | ... }
和Review { ReviewId | Date | ... | ItemId }
其中Review.ItemId
是将每个Review链接到其相应Item的外键。
现在,使用EF Core 6和LINQ(在.NET 6.0上),我使用一些可选的搜索参数获取N行(用于分页)项目。它们按ItemId
排序。对于每个项目,我还添加了从表Review中获取的最后一次审查日期,并设置为Item类的[NotMapped]
属性。
public static List<Item> GetInstruments(Dictionary<string, int> searchParameters, QueryParameters queryParameters)
{
List<Item> items = new();
try
{
using (var dbContext = new DbContext())
{
var dataQuery = dbContext.Items.AsQueryable().AsEnumerable();
if (searchParameters != null)
{
foreach (var searchParameter in searchParameters)
{
if (searchParameter.Key == "SerialNumber")
{
dataQuery = dataQuery.Where(i => i.SerialNumber == searchParameter.Value);
}
if (searchParameter.Key == "Type")
{
dataQuery = dataQuery.Where(i => i.Type == searchParameter.Value);
}
if (searchParameter.Key == "Height")
{
dataQuery = dataQuery.Where(i => i.Height == searchParameter.Value);
}
}
}
var offset = (queryParameters.PageNumber - 1) * queryParameters.RowsPerPage;
if (queryParameters.OrderBy == null)
{
dataQuery = dataQuery.OrderByDescending(i => i.ItemId);
}
else
{
var porpertyInfo = typeof(Item).GetProperty(queryParameters.OrderBy);
if (queryParameters.Ascending == true)
{
dataQuery = dataQuery.AsEnumerable().OrderBy(i => porpertyInfo.GetValue(i, null));
}
else
{
dataQuery = dataQuery.AsEnumerable().OrderByDescending(i => porpertyInfo.GetValue(i, null));
}
}
dataQuery = dataQuery
.Skip(offset)
.Take(queryParameters.RowsPerPage);
items = dataQuery.ToList();
foreach (var instrument in items)
{
instrument.DateLastReview = dbContext.Reviews
.Where(c => c.ItemId == instrument.ItemId)
.Max(c => c.Date);
}
}
}
catch (Exception e)
{
...
}
return items;
}
我之所以这样做是因为我不想先获取整个数据库然后排序,而是先排序再获取(我不知道这是否清楚)。
在使用它之后,我发现最好按最后的Review.Date
排序,但是,同样,我想排序然后获取,我仍然想显示没有评论的项目(如左连接或外部应用)。
首先,我尝试在经典的SQL中做这件事,当我测试它时,它工作了(顺便说一句,如果有更好的方法在SQL中做下面的事情,我也会接受它)
SELECT i.ItemId, i.SerialNumber, i.Type, i.Height, r.Date
FROM Item i
OUTER APPLY
(
SELECT Max(r.Date) as Date
FROM Review r
WHERE r.ItemId = i.ItemId
) r
ORDER BY r.Date DESC
但是我被EF和LINQ难倒了。
我首先尝试只获取项目和审查日期,但我显然做错了。我知道这是不完整的,做我想要的一切,但我首先想只获取项目和LastReviewDate。
var dataQuery = from il in dbContext.Items
select new
{
il,
DateLastReview = dbContext.Reviews
.Where(r => il.ItemId == r.ItemId)
.Max(c => r.Date)
};
所以现在我在这里,因为我不想只是添加一个DateLastReview列到Item表;如果我没有找到任何解决方案,或者您认为它对性能和最佳实践更好,但我不想重复一个字段,我会这样做。
有没有人能帮助我,同时保持排序/排序,然后获取数据的想法。
1条答案
按热度按时间e5nqia271#
不要这样做:
这将导致从数据库中获取所有内容到内存中(而实际上没有获取所需的信息来按相关实体进行排序)。我没有你的设置,但所需的排序可以很简单地用“静态”查询来完成,例如使用以下实体:
这将导致以下SQL(Postgres)用于我的设置:
至于动态查询生成-你-删除
AsEnumerable
调用和反射的东西(var porpertyInfo = typeof(Item).GetProperty(queryParameters.OrderBy);
...),你将需要通过使用一些开关情况或生成expression tree或使用一些第三方库,如System.Linq.Dynamic.Core
或LINQKit
硬编码。参见this answer。