#c# #asp.net-mvc #asp.net-mvc-4 #viewmodel
#c# #asp.net-mvc #asp.net-mvc-4 #viewmodel
Вопрос:
У меня есть две таблицы. Один с сообщениями и один с голосами. Обе таблицы содержат postID (PK / FK). Я хочу сгруппировать все сообщения в таблице голосования и суммировать postVote для каждого сообщения. Затем в представлении, которое я хочу, отобразите сообщение и общее количество голосов за каждое сообщение. Если по этому postID нет голосования, я хочу использовать 0 по умолчанию.
Например, если у меня есть эти данные в таблице post
-------- --------- ------------- ---------
| PostId | Message | MessageDate | User_Id |
-------- --------- ------------- ---------
| 1 | test 1 | 2016-01-01 | 1 |
-------- --------- ------------- ---------
| 2 | test 2 | 2016-01-01 | 1 |
-------- --------- ------------- ---------
| 3 | test 3 | 2016-01-01 | 1 |
-------- --------- ------------- ---------
Таблица голосов
-------- ------------ ---------
| PostId | PostVote | User_Id |
-------- ------------ ---------
| 1 | 1 | 1 |
-------- ------------ ---------
| 1 | 1 | 2 |
-------- ------------ ---------
| 2 | -1 | 1 |
-------- ------------ ---------
Я хочу отобразить это в представлении
Message Vote
Test 1 - 2
Test 2 - -1
Test 3 - 0
Поскольку два пользователя проголосовали 1 (1 1) за postID, один пользователь проголосовал -1 за postID 2, а на postID 3 нет голосов (поэтому в представлении по умолчанию должно быть 0).
Это моя модель post
public class Post
{
public Post()
{
this.Vote = new HashSet<Vote>();
}
public int PostId { get; set; }
public string Message { get; set; }
public DateTime MessageDate { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual ICollection<Vote> Vote { get; set; }
}
Это моя модель голосования
public class Vote
{
[Key, Column(Order = 0)]
public string ApplicationUserID { get; set; }
[Key, Column(Order = 1)]
public int PostId { get; set; }
public virtual Post Post { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public int PostVote { get; set; }
}
Я думаю, я должен использовать Viewmodel и создал это
public class ListPostsViewModel
{
public List<Post> Posts { get; set; }
public List<Vote> Votes { get; set; }
}
Затем я пытаюсь использовать свою ViewModel в контроллере, суммировать голоса на основе postID и объединить сообщения и голоса в представлении. Сейчас это мой контроллер.
var posts = db.Posts.OrderByDescending(p => p.PostId).ToList();
var postsVM = posts.Select(post => new ListPostsViewModel { Posts = posts});
var votes = db.Votes.GroupBy(u => u.PostId)
.Select(v =>
new
{
PostId = v.Key,
TotalVotes = v.Sum(w => w.PostVote) //sum the votes
}).ToList();
var votesVM = posts.Select(post => new ListPostsViewModel { Votes = votes });
И я получаю эту ошибку на votesVM
Невозможно неявно преобразовать тип ‘System.Коллекции.Generic.List<Анонимный тип #1> «в» систему.Коллекции.Generic.List<FreePost.Models.Vote>’
Комментарии:
1. Ваш запрос создает коллекцию анонимных объектов. Вам нужно спроецировать запрос в используемую вами модель
.Select(v => new SomeModel { PostId = v.Key, ...
, но ваш текущийVote
класс не имеет свойства дляTotalVotes
, поэтому вам нужна новая модель. И неясно, как выListPostsViewModel
сможете сгенерировать это представление — ваша модель должна быть коллекцией модели со свойствамиstring Message
иint TotalVotes
2. Вам нужен один запрос с объединением (по
PostId
полю) и выберитеMessage
поле изPost
таблицы и суммуPostVote
полей изVotes
таблицы.3. Не могли бы вы привести мне пример, пожалуйста?
4. Нужно немного поспать, но если вы еще не разобрались с этим, добавлю ответ утром
5. Я предполагаю, что мой контроллер (и viewmodel) ошибочны. Я не хочу иметь свойство для TotalVotes, это вычисленное значение из голосов для просмотра, и я ничего не сохраняю в базе данных. TotalVotes — это сумма всех голосов с одинаковым идентификатором postID.
Ответ №1:
Исключение вызвано тем, что ваш var votes = ...
запрос генерирует коллекцию анонимных объектов, которые затем вы пытаетесь присвоить свойству, которое является List<Vote>
(они не одного типа).
Чтобы сгенерировать желаемое представление, ваша модель представления должна быть
public class PostVoteVM
{
public string Message { get; set; }
public int TotalVotes { get; set; }
}
так что в представлении вы можете использовать
@model IEnumerable<PostVoteVM>
<table>
@foreach(var post in Model)
{
<tr>
<td>@post.Message</td>
<td>@post.TotalVotes </td>
</tr>
}
</table>
Если ваши модели имеют правильные свойства навигации, вам нужен только один запрос, и результаты запроса проецируются в коллекцию модели представления
var model = db.Posts.Include(p => p.Vote) // Include may not be required
.OrderByDescending(p => p.PostId)
.Select(p => new PostVoteVM()
{
Message = p.Message,
TotalVotes = p.Vote.Sum(v => v.PostVote)
});
return View(model);