2016-05-06 2 views
2

Я реализовал код первых дб архитектуры с простым наследованием с помощью ТНР: Database diagramИспользования EF Включить на ТРНЕ

И мне нужно запросить все уведомления о всех типах. TargetUser Недвижимость в NotificationUser стол - это ассоциация. Я пытаюсь выполнить следующий код:

var notifications = _context.Notifications; 
foreach (var notification in notifications) 
{ 
    Debug.WriteLine((notification is NotificationUser)? ((NotificationUser) notification).TargetUser?.Name : "-"); 
} 

В propety базы данных TargetUser устанавливаются для коррекции внешнего ключа, но в коде я не получаю никакого результата. Ложная загрузка включена.

Можно ли загружать пользователей? Я уже пытался написать _context.Notifications.Include('TargetUser') byt, и это исключает.


Обновление. Исключение составляют:

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

Не работает context.Notifications.Include («TargetUser») Похоже, что есть некоторые общие ошибки. Вы сказали, что есть исключение? Могу я увидеть это? –

+0

@AlexanderHaas, попытался выполнить код с включением снова и свойство было загружено правильно. Похоже, у меня была некоторая грамматическая ошибка. Спасибо, в любом случае! – Ivvan

+0

@AlexanderHaas, ладно, он не работает. Я не заметил .OfType () в моем запросе. Без него это исключение. Обновленный вопрос с сообщением. – Ivvan

ответ

0

Уже пробовал много различных решений, и ни один не соответствует моим требованиям, так как я работаю на API, а запрос должен поддерживать разбиение на страницы и делать постоянные запросы к базе данных (а не загружать все сущности в памяти).

Наконец-то выяснилось решение, возможно, не самое лучшее, но достаточно на данный момент. Во-первых, я прошу часть упорядоченных данных (пагинация логики):

var notifications = _context.Notifications 
      .OrderByDescending(n => n.DateTime) 
      .Skip(offset) 
      .Take(limit); 

(На данный момент я не заинтересован в каких-либо свойств) Далее, я получаю идентификаторам нагруженных элементов для каждого типа объекта :

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(); 

все объекты переходит к списку и сортируют еще один раз.

Здесь много плохих вещей, надеюсь, что кто-то может обеспечить лучшее решение.

1

Я не знаю о количестве сущностей, с которыми вы будете работать. Если это возможно, я хотел бы попробовать сделать объединение не на сервере БД:

var userNotifications = _context.Notifications.OfType<NotificationUser>() 
           .Include(n => n.TargetUser).ToList(); 
var placeNotifications = _context.Notifications.OfType<NotificationPlace>().ToList(); 
var notifications = userNotifications.Union(placeNotifications); 

См https://stackoverflow.com/a/27643393/2342504

+0

Фактически, это часть веб-api, а число сущностей может быть действительно большой, поэтому загрузка всех их в память не является хорошей практикой в ​​моем случае. – Ivvan

1

Я знаю, что это старая тема, но я все равно хочу опубликовать некоторые улучшения для тех, кто ищет то же решение.

1.Резервирование сети

Выбор Идентификаторы и затем выполнение запроса, который загружает элементы с идентификаторами избыточны и тот же эффект может быть достигнут, просто запустив эту

Решения:

var userNotifications = _context.Notifications 
    .OrderByDescending(n => n.DateTime) 
    .Skip(offset) 
    .Take(limit) 
    .OfType<NotificationUser>() 
    .Include(n => n.TargetUser) 
    .Include(n => n.TargetUser.Images) 
    .ToList(); 

Таким образом, вы не ожидаете двух соединений DB, но только один. Также вы сохраняете некоторый трафик.

2. Пейджинг на игнорируемых объектах?

Можно предположить, что этот конкретный метод используется только для просмотра объектов унаследованного типа, поэтому я ожидал бы, что Skip и Take будут работать непосредственно только с объектами указанного типа. например Я хочу пропустить 10 NotificationUsers, а не 10 пользователей (из которых только 4 являются NotificationUsers, например).

Решение: Move OfType выше запрос

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. Асинхронный/Await

При написании API, вы должны думать об использовании асинхр/ожидают, что и не блокировать поток, таким образом, тратит меньше ресурсов (для этого, вероятно, потребуется переписать много вашего существующего кода, если вы его еще не используете).

Изучите преимущества 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); 

И сделать этот метод асинхр и вернуть задачу, а

Смежные вопросы