Создайте себе объект модели агрегированного представления, который вы можете использовать для отображения данных в вашем представлении, аналогично тому, что вы получили в сущности Story
на данный момент:
public class UserStoryViewModel
{
public int StoryId { get; set; }
public bool ToRead { get; set; }
public bool Read { get; set; }
public bool WontRead { get; set; }
public bool NotInterested { get; set; }
public byte Rating { get; set; }
...
}
Эта модель представления касается только агрегирования данных для отображения в представлении. Таким образом, вам не нужно искажать существующие сущности, чтобы они соответствовали тому, как вы будете отображать данные в другом месте.
Модели сущностей вашей базы данных должны быть как можно ближе к "немым" объектам (кроме свойств навигации) - они выглядят очень разумно, поскольку они являются моментом.
В этом случае удалите ненужные [NotMapped]
свойства из вашего существующего Story
, который вы добавили ранее.
В вашем контроллере / сервис, вы можете запросить данные в соответствии с вашими случаями использования, которые вы упомянули. Получив результаты запроса, вы можете затем отобразить ваши результаты в вашу модель агрегированного представления для использования в представлении.
Вот пример для варианта использования получения всех Story
с для текущего пользователя:
public class UserStoryService
{
private readonly YourDbContext _dbContext;
public UserStoryService(YourDbContext dbContext)
{
_dbContext = dbContext;
}
public Task<IEnumerable<UserStoryViewModel>> GetAllForUser(string currentUserId)
{
// at this point you're not executing any queries, you're just creating a query to execute later
var allUserStoriesForUser = _dbContext.StoryUserMappings
.Where(mapping => mapping.UserId == currentUserId)
.Select(mapping => new
{
story = _dbContext.Stories.Single(story => story.StoryId == mapping.StoryId),
mapping
})
.Select(x => new UserStoryViewModel
{
// use the projected properties from previous to map to your UserStoryViewModel aggregate
...
});
// calling .ToList()/.ToListAsync() will then execute the query and return the results
return allUserStoriesForUser.ToListAsync();
}
}
Затем можно создать аналогичный метод, чтобы получать только Story
текущего пользователя, которые не отмечены NotInterested
или WontRead
.
Это практически то же самое, что и раньше, но с фильтром в Where
, чтобы гарантировать, что вы не получите те, которые NotInterested
или WontRead
:
public Task<IEnumerable<UserStoryViewModel>> GetForUserThatMightRead(string currentUserId)
{
var storiesUserMightRead = _dbContext.StoryUserMappings
.Where(mapping => mapping.UserId == currentUserId && !mapping.NotInterested && !mapping.WontRead)
.Select(mapping => new
{
story = _dbContext.Stories.Single(story => story.StoryId == mapping.StoryId),
mapping
})
.Select(x => new UserStoryViewModel
{
// use the projected properties from previous to map to your UserStoryViewModel aggregate
...
});
return storiesUserMightRead.ToListAsync();
}
Тогда все, что вам нужно будет сделать, это обновить @model
вашего представления, чтобы использовать ваш новый агрегат UserStoryViewModel
вместо вашей сущности.
Всегда хорошая практика поддерживать хороший уровень разделения между тем, что есть " домен "или код / сущность базы данных из того, что будет использоваться по вашему мнению.
Я бы порекомендовал внимательно прочитать это и продолжать практиковаться, чтобы вы могли выработать правильные привычки и думать, как вы go вперед.
ПРИМЕЧАНИЕ:
Пока st вышеупомянутые предложения должны работать абсолютно нормально (я не проверял локально, поэтому вам, возможно, придется импровизировать / исправить, но вы получите общий смысл) - я бы также рекомендовал несколько других вещей, чтобы дополнить подход выше.
Я хотел бы взглянуть на введение свойства навигации для объекта UserStoryMapping
(если у вас его уже нет; не могу сказать из кода вашего вопроса). Это исключит шаг сверху, когда мы .Select
входим в анонимный объект и добавляем в запрос, чтобы получить Story
s из базы данных, с помощью отображения StoryId
. Вы сможете ссылаться на истории, относящиеся к отображению, просто являясь дочерним навигационным свойством.
Тогда вы также сможете просматривать какую-то библиотеку отображений, а не отображать каждое отдельное свойство себя за каждый звонок. Нечто подобное AutoMapper
сделает свое дело (я уверен, что доступны другие картографы). Вы можете настроить сопоставления, чтобы выполнять всю тяжелую работу между объектами базы данных и просматривать модели. Есть отличная .ProjectTo<T>()
, которая будет проецировать ваши запрашиваемые результаты на желаемый тип, используя те сопоставления, которые вы указали.