我需要查询所有类型的所有通知。
TargetUser
表中的NotificationUser
属性是一个关联。
我试图执行下一个代码:
var notifications = _context.Notifications;
foreach (var notification in notifications)
{
Debug.WriteLine((notification is NotificationUser)? ((NotificationUser) notification).TargetUser?.Name : "-");
}
在数据库中,TargetUser
设置为更正外键,但在代码中我没有得到任何结果。延迟加载已启用。
是否有可能用户急切加载?我已经尝试写_context.Notifications.Include('TargetUser')
,它会引发异常。
UPD。例外是:
A specified Include path is not valid. The EntityType 'Core.Concrete.NotificationBase' does not declare a navigation property with the name 'TargetUser'.
尝试将this answer修改为:
var notifications = _context.Notifications.OfType<NotificationUser>()
.Include(n => n.TargetUser)
.Cast<NotificationBase>()
.Union(_context.Notifications.OfType<NotificationPlace>()
但仍然会抛出相同的异常。
答案 0 :(得分:1)
我不知道您将使用的实体数量。如果可能的话,我会尝试不在DB服务器上进行联合:
var userNotifications = _context.Notifications.OfType<NotificationUser>()
.Include(n => n.TargetUser).ToList();
var placeNotifications = _context.Notifications.OfType<NotificationPlace>().ToList();
var notifications = userNotifications.Union(placeNotifications);
答案 1 :(得分:1)
我知道这是一个老线程,但我仍然希望为寻找相同解决方案的人发布一些改进。
<强> 1。网络冗余
选择ID然后运行查询,加载带有ID的项目是多余的,只需运行此
即可实现相同的效果解决方案:
var userNotifications = _context.Notifications
.OrderByDescending(n => n.DateTime)
.Skip(offset)
.Take(limit)
.OfType<NotificationUser>()
.Include(n => n.TargetUser)
.Include(n => n.TargetUser.Images)
.ToList();
这样,你不是在等待2个DB连接,而只是一个。你也节省了一些流量。
<强> 2。对被忽略的实体进行分页?
可以假设,此特定方法仅用于查看继承类型的实体,因此我希望Skip和Take仅直接在所述类型的实体上工作。例如我想跳过10个NotificationUsers,而不是10个用户(例如,其中只有4个是NotificationUsers)。
解决方案:将类型向上移动到查询
var userNotifications = _context.Notifications
.OfType<NotificationUser>()
.OrderByDescending(n => n.DateTime)
.Skip(offset)
.Take(limit)
.Include(n => n.TargetUser)
.Include(n => n.TargetUser.Images)
.ToList();
第3。异步/等待强>
在编写API时,您应该考虑使用async / await,因为它不会阻塞线程,因此浪费的资源更少(如果您不使用它,可能需要您重写大量现有代码)虽然)。
请研究async / await的优点,并在等待结果的场景中使用它们。
解决方案:更改此
private List<NotificationUser> GetNotificationUsers(int offset, int limit)
{
return _context.Notifications
.OfType<NotificationUser>()
.OrderByDescending(n => n.DateTime)
.Skip(offset)
.Take(limit)
.Include(n => n.TargetUser)
.Include(n => n.TargetUser.Images)
.ToList();
}
进入这个
private async Task<List<NotificationUser>> GetNotificationUsersAsync(int offset, int limit)
{
return await _context.Notifications
.OfType<NotificationUser>()
.OrderByDescending(n => n.DateTime)
.Skip(offset)
.Take(limit)
.Include(n => n.TargetUser)
.Include(n => n.TargetUser.Images)
.ToListAsync();
}
注:的 然后,您还必须从
更改使用此方法的任何位置var x = GetNotificationUsers(skip, take);
到
var x = await GetNotificationUsersAsync(skip, take);
使该方法异步并返回任务
答案 2 :(得分:0)
我已经尝试了很多不同的解决方案,但没有一个符合我的要求,因为我正在开发一个API,并且查询必须支持分页并对数据库进行持续请求(而不是在内存中加载所有实体)。 / p>
终于找到了一个解决方案,也许不是最好的,但现在已经足够了。 首先,我请求一部分有序数据(分页逻辑):
var notifications = _context.Notifications
.OrderByDescending(n => n.DateTime)
.Skip(offset)
.Take(limit);
(此时我对任何属性都不感兴趣)接下来,我将获得每个实体类型的已加载项目的ID:
var ids = notifications.OfType<NotificationUser>().Select(n => n.Id).ToList();
最后加载特定实体,包括所有属性:
var userNotifications = _context.Notifications.OfType<NotificationUser>()
.Include(n => n.TargetUser)
.Include(n => n.TargetUser.Images)
.Where(n => ids.Contains(n.Id))
.ToList();
所有实体进入列表并再次排序。
这里有很多不好的东西,希望有人能提供更好的解决方案。