Html form doesn't send double variable to controller - c#

I have html form:
#using (Html.BeginForm("ShowAddedProduct", "AddProductsDialog",FormMethod.Post,
new {id="AddProdForm" }))
{
<p>Price:</p>#Html.TextBoxFor(x => x.Price, new { type="number",Class = "EnterProductInfoField"});
#Html.ValidationMessageFor(x => x.Price);
<input id="submitValidation" type="submit" value="Add" />
}
If i enter integer value in textbox like 700.It sends valid Price field for model to ShowAddedProduct Action method ,but when i enter decimal number like 422.65,it doesn't sends it and i get in action method Price=0.Type of Price is double
Here is ShowAddedProduct method code.
[HttpPost]
public ActionResult ShowAddedProduct(Product product, HttpPostedFileBase uploadedImage)
{
product.DateAdded = DateTime.Now;
if (uploadedImage != null && uploadedImage.ContentLength > 0)
{
using (BinaryReader reader = new BinaryReader(uploadedImage.InputStream))
{
product.Picture = reader.ReadBytes(uploadedImage.ContentLength);
}
}
using (GoodsContainer1 container = new GoodsContainer1())
{
product.SubCategory = container.SubCategorySet.FirstOrDefault(x => x.Id == product.SubCategory_Id);
if (product.Article != null
&& product.Name != null
&& product.Picture != null
&& product.Price != 0)
{
container.ProductSet.Add(product);
container.SaveChanges();
return PartialView("~/Views/AddProductsDialog/AddedProduct.cshtml",product);
}
}
return RedirectToAction("AddProducts");
}
Here is model code for html form.
public partial class Product
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Product()
{
this.DescriptionParameters = new HashSet<DescriptionParameters>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Article { get; set; }
public double Price { get; set; }
public byte[] Picture { get; set; }
public System.DateTime DateAdded { get; set; }
public int SubCategory_Id { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<DescriptionParameters> DescriptionParameters { get; set; }
public virtual SubCategory SubCategory { get; set; }
}
}

It is because of mvc internal annotation. change
#Html.TextBoxFor(x => x.Price, new { type="number",Class = "EnterProductInfoField"})
to
#Html.EditorFor(x => x.Price, new { type="number",Class = "EnterProductInfoField"})

#Html.TextBoxFor(x => x.Price, new { Class = "EnterProductInfoField"})
Delete type="number", because it sets your value as integer (not double)

Related

Model comes null to controller

This is my first ask. I have 2 models for 1 view. I built the code but i have a problem. data comes null from view to controller.
Models:
Mom model:
public class BildirimOlusturViewModel
{
public BildirimOlusturModel bildirimOlusturModel { get; set; }
public TagBoxViewModel tagBoxViewModel { get; set; }
}
Child models:
public class BildirimOlusturModel
{
[Required(ErrorMessage = "Lütfen bildirim tipi seçiniz")]
public string BildirimTipi { get; set; }
[Required(ErrorMessage = "Lütfen alıcı tipi seçiniz")]
public string AliciTipi { get; set; }
[Required(ErrorMessage = "Lütfen alıcı seçiniz")]
public string Alicilar { get; set; }
[Required(ErrorMessage = "Lütfen bir başlık giriniz")]
public string Baslik { get; set; }
[Required(ErrorMessage = "Mesaj boş olamaz")]
public string Mesaj { get; set; }
}
public class TagBoxViewModel
{
public List<string> Items { get; set; }
}
View:
#model xyz.Web.Notifications.Models.BildirimOlusturViewModel
<form method="post" asp-controller="Bildirim" asp-action="BildirimOlustur">
...
#(Html.DevExtreme().SelectBoxFor(s => s.bildirimOlusturModel.AliciTipi)
.Placeholder("Alıcı Tipi...")
.DataSource(new List<SelectListItem> {
new SelectListItem
{
Text = "Personel",
Value = "personel".ToString()
},
new SelectListItem
{
Text = "Müşteri",
Value = "musteri".ToString()
}})
.ValueExpr("Value").DisplayExpr("Text")
.OnValueChanged("alicitipi_changed")
.ID("slcAliciTipi")
)
</div>
<div class="col-md-8">
#(Html.DevExtreme().TagBoxFor(x => x.bildirimOlusturModel.Alicilar)
.Items(Model.tagBoxViewModel.Items)
.SearchEnabled(true)
.Placeholder("Alıcı...")
.ID("TagBoxAlici")
)
#(Html.DevExtreme().TextBoxFor(x => x.bildirimOlusturModel.Baslik)
.Placeholder("Başlık...")
)
<input type="text" id="Mesaj" asp-for="bildirimOlusturModel.Mesaj" name="bildirimOlusturModel.Mesaj" id="bildirimOlusturModel.Mesaj"/>
#(Html.DevExtreme().Button()
.Text("Submit")
.Type(ButtonType.Default)
.StylingMode(ButtonStylingMode.Contained)
.Width(120)
.UseSubmitBehavior(true)
)
</form>
Controller:
[HttpPost]
public IActionResult BildirimOlustur(BildirimOlusturModel model)
{
string sAlicilar = model.Alicilar;
string sAliciTipi = model.AliciTipi;
string sBaslik = model.Baslik;
string sBildirimTipi = model.BildirimTipi;
string sMesaj = model.Mesaj;
}
Submit button sends me inside the post method but not sends the model. My variables coming null. Thank you for help.
Try adding a [FromBody] attribute before your argument.
public IActionResult BildirimOlustur([Frombody] BildirimOlusturModel model)
I solved the problem. controller was waiting for the wrong parameter.
[HttpPost]
public IActionResult BildirimOlustur(BildirimOlusturViewModel model)
{
BildirimOlusturModel mdl = new BildirimOlusturModel();
mdl = model.bildirimOlusturModel;
string sAlicilar = mdl.Alicilar;
}

Model Binding properties null on asp.net core 3 MVC

could anyone tell me what am I doing wrong? I am getting null properties trying to bind.
Explaining:
My Controller Index looks ok, so that in my View I can see all the input values that I want to bind filled (IdPedidoAtendimento,PedidoAtendimentoTaxa,HorarioAgendado,IdPedidoTipoPagamento,IdUnidadeUsuario).
So far, everything looks good. But, after submit the page, in my Controller CheckOut all the properties in checkOut object binded is null, as you can see in the picture.
It was working fine, I dont know what I did so that it now is getting null properties.
I am using asp.net core 3.1 MVC
ViewModel
public class CheckOut
{
public Usuario Usuario { get; set; }
public UsuarioUnidade UsuarioUnidade { get; set; }
public CatalogoEndereco CatalogoEndereco { get; set; }
public UsuarioPagamento UsuarioPagamento { get; set; }
public byte IdPedidoAtendimento { get; set; }
public string PedidoAtendimentoNome { get; set; }
public decimal PedidoAtendimentoTaxa { get; set; }
public DateTime? HorarioAgendado { get; set; }
public byte IdPedidoTipoPagamento { get; set; }
public string PedidoTipoPagamento { get; set; }
public int IdUnidadeUsuario { get; set; }
public string Nome { get; set; }
public string NumEndereco { get; set; }
public string ComplementoEndereco { get; set; }
public string RuaNome { get; set; }
public string CidadeNome { get; set; }
public string EstadoNome { get; set; }
public string CEP { get; set; }
public byte? isCPF { get; set; }
public string CPF { get; set; }
public string NumeroCartao { get; set; }
public string CodCartao { get; set; }
}
Controller
public IActionResult Index()
{
var user = User.FindFirst(ClaimTypes.Name);
if (user != null)
{
Usuario usuario = new Usuario();
usuario = _context.Usuario
.SingleOrDefault(u => u.Email.Equals(user.Value) && u.IsAtivo == true);
CatalogoEndereco catalogoEndereco = new CatalogoEndereco();
catalogoEndereco = _context.CatalogoEndereco
.Where(c => c.IdUsuario.Equals(usuario.IdUsuario) && c.IsAtivo == true && c.IsPrincipal == true)
.SingleOrDefault();
UsuarioPagamento usuarioPagamento = new UsuarioPagamento();
usuarioPagamento = _context.UsuarioPagamento
.Where(c => c.IdUsuario.Equals(usuario.IdUsuario) && c.IsPrincipal == true)
.SingleOrDefault();
UsuarioUnidade usuarioUnidade = new UsuarioUnidade();
usuarioUnidade = _context.UsuarioUnidade
.Where(c => c.IdUsuario.Equals(usuario.IdUsuario) && c.IdUnidadeNavigation.IsAtiva == true && c.IsPrincipal == true)
.SingleOrDefault();
UsuarioAtendimento usuarioAtendimento = new UsuarioAtendimento();
usuarioAtendimento = _context.UsuarioAtendimento
.Where(c => c.IdUsuario.Equals(usuario.IdUsuario) && c.IsPrincipal == true)
.SingleOrDefault();
CheckOut checkOut = new CheckOut()
{
Usuario = usuario,
UsuarioUnidade = usuarioUnidade,
CatalogoEndereco = catalogoEndereco,
UsuarioPagamento = usuarioPagamento,
IdPedidoAtendimento = usuarioAtendimento.Tipo,
PedidoAtendimentoNome = _context.PedidoAtendimento
.FirstOrDefault(t => t.IdPedidoAtendimento == usuarioAtendimento.Tipo).Nome,
PedidoAtendimentoTaxa = _context.PedidoAtendimento
.FirstOrDefault(t => t.IdPedidoAtendimento == usuarioAtendimento.Tipo).Taxa
};
if (usuarioAtendimento.Tipo == 1)
{
checkOut.Nome = usuario.Nome;
if (usuarioUnidade != null)
{
checkOut.IdUnidadeUsuario = usuarioUnidade.IdUnidade;
}
if (catalogoEndereco != null)
{
checkOut.RuaNome = catalogoEndereco.IdEnderecoLogradouroNavigation.IdRuaNavigation.Nome;
checkOut.CidadeNome = catalogoEndereco.IdEnderecoLogradouroNavigation.IdCidadeNavigation.Nome;
checkOut.EstadoNome = catalogoEndereco.IdEnderecoLogradouroNavigation.IdEstadoNavigation.Nome;
checkOut.NumEndereco = catalogoEndereco.NumEndereco;
checkOut.ComplementoEndereco = catalogoEndereco.Complemento;
checkOut.CEP = catalogoEndereco.IdEnderecoLogradouroNavigation.Cep;
}
}
else if (usuarioAtendimento.Tipo == 2)
{
if (usuarioUnidade != null)
{
checkOut.IdUnidadeUsuario = usuarioUnidade.IdUnidade;
checkOut.Nome = usuarioUnidade.IdUnidadeNavigation.Nome;
checkOut.RuaNome = usuarioUnidade.IdUnidadeNavigation.IdEnderecoLogradouroNavigation.IdRuaNavigation.Nome;
checkOut.CidadeNome = usuarioUnidade.IdUnidadeNavigation.IdEnderecoLogradouroNavigation.IdCidadeNavigation.Nome;
checkOut.EstadoNome = usuarioUnidade.IdUnidadeNavigation.IdEnderecoLogradouroNavigation.IdEstadoNavigation.Nome;
checkOut.NumEndereco = usuarioUnidade.IdUnidadeNavigation.NumEndereco;
checkOut.CEP = usuarioUnidade.IdUnidadeNavigation.IdEnderecoLogradouroNavigation.Cep;
}
}
if (usuarioPagamento != null)
{
checkOut.IdPedidoTipoPagamento = usuarioPagamento.Tipo;
checkOut.PedidoTipoPagamento = _context.PedidoTipoPagamento
.FirstOrDefault(t => t.IdPedidoTipoPagamento == usuarioPagamento.Tipo).Nome;
checkOut.isCPF = 0;
checkOut.CPF = usuario.Cpf;
checkOut.NumeroCartao = null;
checkOut.CodCartao = null;
if (usuarioPagamento.Tipo == 1 || usuarioPagamento.Tipo == 2)
{
checkOut.NumeroCartao = "**** " + usuarioPagamento.Numero.Substring(12, 4);
checkOut.CodCartao = null;
}
}
return View(checkOut);
}
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CheckOut([Bind("IdPedidoAtendimento,PedidoAtendimentoTaxa,HorarioAgendado,IdPedidoTipoPagamento,IdUnidadeUsuario")] CheckOut checkOut)
{
if (ModelState.IsValid)
{
var user = User.FindFirst(ClaimTypes.Name);
if (user != null)
{
var cliente = _context.Usuario.SingleOrDefault(u => u.Email.Equals(user.Value));
var pedido = new Pedido()
{
IdUsuario = cliente.IdUsuario,
IdUnidade = checkOut.IdUnidadeUsuario,
IdPedidoCanalVenda = 1,
IdPedidoAtendimento = checkOut.IdPedidoAtendimento,
IdAtendente = null,
IdPedidoTipoPagamento = checkOut.IdPedidoTipoPagamento,
IdEntregador = null,
IdPedidoStatus = 1,
DataPedido = DateTime.Now,
DataEntrega = null,
HorarioAgendado = null,
TaxaServico = checkOut.PedidoAtendimentoTaxa
};
_context.Pedido.Add(pedido);
await _context.SaveChangesAsync()
.ConfigureAwait(false);
int lastPedido = pedido.IdPedido;
List<Carrinho> cart = JsonSerializeSessionHelper.Get<List<Carrinho>>(HttpContext.Session, "cart");
foreach (var item in cart)
{
var pedidoItens = new PedidoItens
{
IdPedido = lastPedido,
IdProduto = item.IdProduto,
IdProdutoTamanho = item.IdProdutoTamanho,
IdProdutoTipoMassa = item.IdProdutoTipoMassa,
IdProdutoMeia = item.IdProdutoMeia,
Quantidade = item.Quantidade,
Preco = item.Preco
};
_context.PedidoItens.Add(pedidoItens);
}
await _context.SaveChangesAsync()
.ConfigureAwait(false);
TempData["save"] = "Pedido realizado com sucesso";
HttpContext.Session.Remove("cart");
}
else
{
return RedirectToAction("Index", "Login");
}
return RedirectToAction("Index", "Pedido");
}
return View(checkOut);
}
View
#using (Html.BeginForm("CheckOut", "Carrinho", FormMethod.Post))
{
<button type="submit" class="btn btn-info btn-sm">
Pagar (R$ #(#ViewBag.SubTotal + Model.PedidoAtendimentoTaxa))
</button>
// I need these values for Bind!!
#*#Html.DisplayFor(m => m.IdPedidoAtendimento)
#Html.DisplayFor(m => m.PedidoAtendimentoTaxa)
#Html.DisplayFor(m => m.HorarioAgendado)
#Html.DisplayFor(m => m.IdPedidoTipoPagamento)
#Html.DisplayFor(m => m.IdUnidadeUsuario)*#
<input asp-for="IdPedidoAtendimento" value="#Model.IdPedidoAtendimento" id="txtIdPedidoAtendimento" name="txtIdPedidoAtendimento" hidden/>
<input asp-for="PedidoAtendimentoTaxa" value="#Model.PedidoAtendimentoTaxa" id="txtPedidoAtendimentoTaxa" name="txtPedidoAtendimentoTaxa" hidden/>
<input asp-for="HorarioAgendado" value="#Model.HorarioAgendado" id="txtHorarioAgendado" name="txtHorarioAgendado" hidden />
<input asp-for="IdPedidoTipoPagamento" value="#Model.IdPedidoTipoPagamento" id="txtIdPedidoTipoPagamento" name="txtIdPedidoTipoPagamento" hidden/>
<input asp-for="IdUnidadeUsuario" value="#Model.IdUnidadeUsuario" id="txtIdUnidadeUsuario" name="txtIdUnidadeUsuario" hidden/>
}
Model binding occurs based on the name attribute. You have the #Html.DisplayFor lines commented out, so it isn't binding there. For the <input> fields, you have manually entered a name of txt<PropertyName>, so it isn't binding on those, either.
ASP.NET will automatically create an appropriate name attribute just using the asp-for attribute to accommodate model binding.

ModelState Error c# mvc5

In an Action Result that does a HttpPost i get an error from EF
"ModelState.Errors Internal error in the expression evaluator"
My model in View is OrdineOmaggio
public partial class OrdineOmaggio
{
public int Id { get; set; }
public string Id_Gioielleria { get; set; }
public System.DateTime Data_Ordine { get; set; }
public virtual Consumatore MD_CONSUMATORE { get; set; }
public virtual Omaggio MD_OMAGGIO { get; set; }
public virtual CodiceRandomConsumatore MD_RANDOM_CONSUMATORE { get; set; }
}
My Action is so
public async Task<ActionResult> ChooseGift(
[Bind(Include ="Data_Ordine,MD_RANDOM_CONSUMATORE,MD_OMAGGIO,Id_Gioielleria")]
OrdineOmaggio ordineOmaggio,
string codiceOmaggio, string codice)
{
var randomConsumatore = _context.CodiciRandomConsumatori
.SingleOrDefault(c => c.Codice == codice) ??
new CodiceRandomConsumatore
{
Id = -1,
Codice = "",
Assegnato = null,
Distinzione = ""
};
var consumatore = _context.CodiciRandomConsumatori
.Where(c => c.Codice == codice)
.Select(c => c.MD_CONSUMATORE)
.SingleOrDefault();
var omaggio = _context.Omaggi
.SingleOrDefault(c => c.CodiceOmaggio == codiceOmaggio);
if (ModelState.IsValid)
{
ordineOmaggio.Data_Ordine = DateTime.Now;
ordineOmaggio.Id_Gioielleria = ordineOmaggio.Id_Gioielleria;
ordineOmaggio.MD_CONSUMATORE = consumatore; // FK
ordineOmaggio.MD_OMAGGIO = omaggio; // FK
ordineOmaggio.MD_RANDOM_CONSUMATORE = randomConsumatore; // FK
_context.OrdiniOmaggio.Add(ordineOmaggio);
randomConsumatore.Assegnato = true;
_context.SaveChanges();
return RedirectToAction("Success");
}
return View(ordineOmaggio);
}
The error is about dataAnnotation: it say that not all field all filled
The metadata is
public class OrdineOmaggioMetadata
{
[Required(ErrorMessage = "Scegli la gioiellereia.")]
public string Id_Gioielleria;
[Required(ErrorMessage = "Seleziona una foto.")]
public Omaggio MD_OMAGGIO;
...
}
In my view i placed
#Html.HiddenFor(m=> m.MD_OMAGGIO.CodiceOmaggio)
#Html.ValidationMessageFor(m => m.MD_OMAGGIO.CodiceOmaggio)
but this helper pass null to ActionResult
MD_OMAGGIO is a table foreign key for product codes.
what i wrong ?

asp.net mvc5 - Passing selected list item ids back to controller

I have a view model containing the information that I am using for a drop-down list on a view:
public class AddPlayersToGame
{
public string GameTitle { set; get; }
public int GameID { set; get; }
public List<SelectListItem> Players { set; get; }
public int PlayerID { get; set; }
public int[] SelectedPlayers { set; get; }
}
This is my View which simply displays a drop-down list containing the list of Players to select from:
#model WebGameProj.ViewModels.AddPlayersToGame
<div>
{
#Html.DropDownListFor(x => Model.PlayerID, Model.Players)
<input type="submit" />
}
</div>
This is the controller methods I am using:
public ActionResult AddPlayersView(int id)
{
var GameSelected = db.Games.Find(id);
if (GameSelected== null)
{
return HttpNotFound();
}
var np = new AddPlayersToGame { GameID = id, GameTitle = GameSelected.GameTitle };
np.Players = db.Players.Select(m => new SelectListItem
{
Text = m.PlayerUserName,
Value = m.PlayerId.ToString()
}).ToList();
return View(np);
}
[HttpPost]
public ActionResult AddPlayersView(AddPlayersToGame model)
{
foreach (var item in model.SelectedPlayers)
{
var SelPlayer = db.Players.Find(model.PlayerID);
if (SelPlayer== null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (SelPlayer != null)
{
Game GameSelected = new Game();
GameSelected.GamePlayers.Add(SelPlayer);
db.Entry(GameSelected).State = EntityState.Modified;
db.SaveChanges();
}
}
return RedirectToAction("GameDetailsView");
}
So, basically I want to have a view that displays a drop-down list of players and when some players are selected the post method will then find each player on the database by using their ids that are being passed back via the drop-down list on the view, then add them to a the current list of players for that game.
Change your model to
public class AddPlayersToGame
{
public string GameTitle { set; get; }
public int GameID { set; get; }
public int PlayerID { get; set; }
public int[] PlayerIds { set; get; }
public List<SelectListItem> Players { set; get; }
}
And your view to
#model WebGameProj.ViewModels.AddPlayersToGame
<div>
{
#Html.ListBoxFor(x => x.PlayerIds, Model.Players)
<input type="submit" />
}
</div>
You should then have the selects ids in the model after submitting.
You can also try:
Model
public class AddPlayersToGame
{
public string GameTitle { set; get; }
public int GameID { set; get; }
public int[] PlayerIDs { get; set; }
public MultiSelectList Players { get; set; }
}
Controller
public ActionResult AddPlayersView(int id)
{
var GameSelected = db.Games.Find(id);
if (GameSelected== null)
{
return HttpNotFound();
}
var np = new AddPlayersToGame { GameID = id, GameTitle = GameSelected.GameTitle };
var playerList = db.Players.Select(m => new
{
PlayerUserName = m.PlayerUserName,
PlayerId = m.PlayerId
}).ToList();
np.Players = new MultiSelectList(playerList, "PlayerIDs", "PlayerUserName");
return View(np);
}
[HttpPost]
public ActionResult AddPlayersView(AddPlayersToGame model)
{
foreach (var playerID in model.PlayerIDs)
{
var SelPlayer = db.Players.Find(playerID);
if (SelPlayer== null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (SelPlayer != null)
{
Game GameSelected = new Game();
GameSelected.GamePlayers.Add(SelPlayer);
db.Entry(GameSelected).State = EntityState.Modified;
db.SaveChanges();
}
}
return RedirectToAction("GameDetailsView");
}
View
#model WebGameProj.ViewModels.AddPlayersToGame
<div>
{
#Html.ListBoxFor(x => x.PlayerIDs, Model.Players)
<input type="submit" />
}
</div>

How to count nested collection from database using Entity Framework

I'm making my first Asp.net Mvc application - Forum System.
I'm trying to display how many posts and threads there are in sub category.
This are my tables:
public class Category
{
private ICollection<SubCategory> subCategories;
public Category()
{
this.subCategories = new HashSet<SubCategory>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<SubCategory> SubCategories
{
get { return this.subCategories; }
set { this.subCategories = value; }
}
}
public class SubCategory
{
private ICollection<Thread> threads;
public SubCategory()
{
this.threads = new HashSet<Thread>();
}
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
public virtual ICollection<Thread> Threads
{
get { return this.threads; }
set { this.threads = value; }
}
}
public class Thread
{
private ICollection<Post> posts;
public Thread()
{
this.posts = new HashSet<Post>();
}
public int Id { get; set; }
public string Title { get; set; }
public virtual SubCategory SubCategory { get; set; }
public int SubCategoryId { get; set; }
public virtual ICollection<Post> Posts
{
get { return this.posts; }
set { this.posts = value; }
}
public string AuthorId { get; set; }
public virtual ApplicationUser Author { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Content { get; set; }
public int ThreadId { get; set; }
public virtual Thread Thread { get; set; }
public string AuthorId { get; set; }
public virtual ApplicationUser Author { get; set; }
}
this is my view:
#model IEnumerable<ForumSystem.Web.ViewModels.Home.IndexCategoryViewModel>
#{
ViewBag.Title = "Home Page";
}
<div class="container">
#foreach (var category in Model)
{
<div class="row">
<h5>#category.Name</h5>
#foreach (var subCat in category.SubCategories)
{
<div class="col-md-10">
<div class="row">
<h7>
#subCat.Title
</h7>
</div>
<div class="row">
<p>#subCat.Description</p>
</div>
</div>
<div class="col-md-2">
<p>#category.ThreadsCount threads</p>
<p>#category.PostsCount posts</p>
<div class="row">
</div>
</div>
}
</div>
}
</div>
#category.ThreadsCount and PostsCount are not working.
I can get easy threads count in view with #subCategory.Threads.Count, but I can't get posts count.
In controller I have tried many things.
The code in the moment is :
public ActionResult Index()
{
var threadScount = this.Data
.SubCategories
.All()
.SelectMany(x => x.Threads)
.Count();
var postsCount = this.Data
.Threads
.All()
.SelectMany(x => x.Posts)
.Count();
var model = this.Data
.Categories
.All()
.Select(c => new IndexCategoryViewModel
{
Name = x.Name,
SubCategories = c.SubCategories,
ThreadsCount = threadScount,
PostsCount = postsCount,
})
.ToList();
return this.View(model);
}
But this gives me all threads and posts count, not specific for each subCategory.
Thanks in advance.
Create view models that represent what you want to display
public class SubCategoryVM
{
public string Title { get; set; }
public string Description { get; set; }
public int ThreadsCount { get; set; }
public int PostCount { get; set; }
}
public class CategoryVM
{
public string Name { get; set; }
public List<SubCategoryVM> SubCategories { get; set; }
}
Controller
public ActionResult Index()
{
var model = this.Data.Categories.Select(c => new CategoryVM
{
Name = c.Name,
SubCategories = c.SubCategories.Select(s => new SubCategoryVM
{
Title = s.Title,
Description = s.Description,
ThreadsCount = s.Threads.Count,
PostsCount = s.Threads.SelectMany(t => t.Posts).Count;
})
});
return View(model);
}
View
#model IEnumerable<CategoryVM>
#{
ViewBag.Title = "Home Page";
}
<div class="container">
#foreach (var category in Model)
{
<div class="row">
<h5>#category.Name</h5>
#foreach (var subCategory in category.SubCategories)
{
<div class="col-md-10">
<div class="row">
<h7>
// The following line in your view makes no sense
// #subCat.Title
// Assuming you have method: public ActionResult Details(string title) in SubCategoryController, then
#Html.ActionLink(subCategory.Title, "Details", "SubCategory", new { title = subCategory.Title }, null)
</h7>
</div>
<div class="row">
<p>#subCategory.Description</p>
</div>
</div>
<div class="col-md-2">
<p><span>#subCategory.ThreadCount</span><span>threads</span></p>
<p><span>#subCategory.PostCount</span><span>posts</span></p>
</div>
}
</div>
}
</div>
I believe what you're looking for is this:
var model = this.Data
.Categories
.Select(c => new IndexCategoryViewModel
{
Name = c.Name,
SubCategories = c.SubCategories,
ThreadsCount = c.Threads.Count(),
PostsCount = c.Threads.Sum(t => t.Posts.Count()),
})
.ToList();
Here you create nested queries to count threads and posts for each category. You don't need the threadsCount and postsCount since they store overall counts and not per-category counts.
NOTE
I assume that Threads property exists on category class and Posts property exists on thread class. Otherwise you'll need to have predicates to associate posts with threads and threads with categories. Most commonly they would be ids, in which case the code would look similar to this:
var model = this.Data
.Categories
.Select(c => new IndexCategoryViewModel
{
Name = c.Name,
SubCategories = c.SubCategories,
ThreadsCount = this.Data
.Threads
.Count(t => t.CategoryId == c.Id),
PostsCount = this.Data
.Posts
.Count(p => this.Data
.Threads
.Any(t => p.ThreadId == t.Id && t.CategoryId == c.Id)
),
})
.ToList();
Notice that I also skipped all .All() calls since they seem redundant, although I'm not sure what they do so you can throw it back in there if necessary.
Try this, also you will need to change the ViewModel to reflect requirements
public ActionResult Index()
{
var model = from subCategory in this.Data.SubCategories
select new SubCategoryViewModel
{
Name = subCategory.Category.Name,
SubCategory = subCategory,
ThreadsCount = subCategory.Threads.Count(),
PostsCount = subCategory.Threads.SelectMany(c => c.Posts).Count(),
})
.ToList();
return this.View(model);
}

Categories