This is my first post so I apologize for my lack of awareness.
I am trying to select a number of items linked to a category, based on the selected categories ID. I know I need to somehow utilize the created list in the model, but I am not sure how.
In other words, I want to list Menu Items on the Category "Details" view, based on which category is selected on the site.
MenuCategory Model
public class MenuCategory
{
public int MenuCategoryId
{
get;
set;
}
public string Name
{
get;
set;
}
public List<MenuItem> MenuItems
{
get;
set;
}
}
MenuItem Model
public class MenuItem
{
public int MenuItemId
{
get;
set;
}
public string Name
{
get;
set;
}
public string Image
{
get;
set;
}
[ForeignKey("MenuCategory")]
public int MenuCategoryId
{
get;
set;
}
public MenuCategory MenuCategory
{
get;
set;
}
}
MenuCategory View Index
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
<a asp-controller="MenuCategories" asp-action="Details" asp-route-id="#item.MenuCategoryId">
Details
</a>
</td>
</tr>
}
</tbody>
MenuCategory Details View
#model Farbucks.Models.MenuCategory
#{
ViewData["Title"] = "Details";
}
<h2>Details</h2>
<div>
<h4>MenuCategory</h4>
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.Name)
</dt>
</dl>
</div>
#foreach (var item in Model.MenuItems)
{
#Html.DisplayFor(modelItem => item.Name)
}
MenuCategories Controller
{
public class MenuCategoriesController : Controller
{
private readonly ApplicationDbContext _context;
public MenuCategoriesController(ApplicationDbContext context)
{
_context = context;
}
// GET: MenuCategories
public async Task<IActionResult> Index()
{
return View(await _context.MenuCategory.ToListAsync());
}
// GET: MenuCategories/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var menuCategory = await _context.MenuCategory
.FirstOrDefaultAsync(m => m.MenuCategoryId == id);
if (menuCategory == null)
{
return NotFound();
}
return View(menuCategory);
}
}
}
MenuItems Controller
{
public class MenuItemsController : Controller
{
private readonly ApplicationDbContext _context;
public MenuItemsController(ApplicationDbContext context)
{
_context = context;
}
// GET: MenuItems
public async Task<IActionResult> Index()
{
var applicationDbContext = _context.MenuItem.Include(m => m.MenuCategory);
return View(await applicationDbContext.ToListAsync());
}
// GET: MenuItems/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var menuItem = await _context.MenuItem
.Include(m => m.MenuCategory)
.FirstOrDefaultAsync(m => m.MenuItemId == id);
if (menuItem == null)
{
return NotFound();
}
return View(menuItem);
}
}
}
In MenuCategory Details View, You can get list of MenuItems by using Lazy loading in entity
So it looks like the snipped below:
MenuCategory Details View
foreach(var item in Model.MenuItems)
{
// display information of Menu item here.
}
I wanted to redirect "Edit" Actionlink to a another page from Index.cshtml page and the directions in the tab shows "http://localhost:49712/Home/Edit/id". The data are shown in "Index.cshtml" in a table but not all data is shown (just some of it). Then, when I want to edit the data, the edit page shows "HTTP Error 404.0 - Not Found". I think this is because of the attributes got clash or anything?
This is the "Index.cshtml" for the table:-
foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.NUMBER)
</td>
<td>
#Html.DisplayFor(modelItem => item.TITLE)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ID}) |
#Html.ActionLink("Details", "Details", new { id = item.ID}) |
#Html.ActionLink("Delete", "Delete", new { id = item.ID})
</td>
</tr>
}
This is the edit part in controller":-
// GET: Home/Edit/5
public async Task<ActionResult> Edit(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Tests test= await db.Test.FindAsync(id);
if (test== null)
{
return HttpNotFound();
}
return View(test);
}
// POST: Home/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "ID,YEAR,LANGUAGE,COUNTRY,SUBJECT,NUMBER,TITLE] Tests test)
{
if (ModelState.IsValid)
{
db.Entry(test).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(test);
}
This is my model:-
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
public partial class Tests
{
public string ID{ get; set; }
public Nullable<int> YEAR { get; set; }
public string LANGUAGE { get; set; }
public string COUNTRY { get; set; }
public string SUBJECT { get; set; }
public string NUMBER { get; set; }
public string TITLE { get; set; }
}
}
As you can see, some of the attributes does not shown in data table in "Index.cshtml", but all of them will be shown in edit page. How can I do this? Any help from anyone would be highly appreciated.
I am totally new to programming so my question maybe confusing but I will try to explain as best as I can.
So I build a app that take in ratings between 1-5. The result is stored in the data base. But I do not understand how to put some logic in my model class where it can retrieve that number and out output the number the users input and the overall average of the rating it was given.
This is my Model class:
public class MovieReview : IValidatableObject
{
public int Id { get; set; }
[Range(1,10)]
[Required]
public double Rating { get; set; }
[Required]
[StringLength(1024)]
public string Comment { get; set; }
[Display(Name="User Name")]
[DisplayFormat(NullDisplayText="anonymous")]
//[MaxWord(5)]
public string ReviewerName { get; set; }
public int MovieId { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(Rating < 2 && ReviewerName.ToLower().StartsWith("keith"))
{
yield return new ValidationResult("Scorry, Keith uou can't do this");
}
//throw new NotImplementedException();
}
}
public partial class MovieReview : IValidatableObject
{
public ICollection<AverageRating>
public int Id { get; set; }
public int AverageRating { get _AverageRating(c => c.AverageRating; set; }
}
}
This is my controller:
namespace YayOrNay.Controllers
{
public class ReviewsController : Controller
{
YayOrNayDb _db = new YayOrNayDb();
// GET: Reviews
public ActionResult Index([Bind(Prefix = "id")]int movieId)
{
var movie = _db.Movies.Find(movieId);
if(movie !=null)
{
return View(movie);
}
return HttpNotFound();
}
[HttpGet]
public ActionResult Create (int movieId)
{
return View();
}
[HttpPost]
public ActionResult Create(MovieReview review)
{
if(ModelState.IsValid)
{
_db.Reviews.Add(review);
_db.SaveChanges();
return RedirectToAction("Index", new { id = review.MovieId });
}
return View(review);
}
[HttpGet]
public ActionResult Edit (int id)
{
var model = _db.Reviews.Find(id);
return View(model);
}
//[Bind(Exclude = "ReviewerName")]
[HttpPost]
public ActionResult Edit (MovieReview review)
{
if (ModelState.IsValid)
{
_db.Entry(review).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index", new { id = review.MovieId });
}
return View(review);
}
protected override void Dispose(bool disposing)
{
_db.Dispose();
base.Dispose(disposing);
}
}
}
And this is my view:
#model IEnumerable<YayOrNay.Models.MovieReview>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Rating)
</th>
<th>
#Html.DisplayNameFor(model => model.Comment)
</th>
<th>
#Html.DisplayNameFor(model => model.ReviewerName)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Rating)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comment)
</td>
<td>
#Html.DisplayFor(modelItem => item.ReviewerName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
</td>
</tr>
}
</table>
I hope this is enough information for you to understand what I am trying to do.
I am trying to restrict user entries so that only that specific user is able to see their entries and not anyone else. In other words, after all I've done, my application still displays every entry that was ever entered; and any user is able to see the entries.
I've created a one-to-many relationship by referencing the foreign key from my Expenses table to the primary key of my AspNetUsers using the Code First convention in Entity Framework, however, when I log in as different users, I am still able to see entries (expenses) that other users have entered.
I'm not sure whether the problem lies in my view, model, or controller.
Here is the code I currently have:
IdentityModel:
public class ApplicationUser : IdentityUser
{
public ApplicationUser()
{
Expenses = new List<Expense>();
}
[Required]
public string Fullname { get; set; }
[Required]
public string Province { get; set; }
[Required]
public string Company { get; set; }
public virtual ICollection<Expense> Expenses { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("PacificPetEntities", throwIfV1Schema: false)
{
}
public IDbSet<Expense> Expenses { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Expense Model:
public class Expense : IValidatableObject
{
public Expense() { }
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required]
public string Category { get; set; }
public string Description { get; set; }
[Required]
[Display(Name = "Gross Amount")]
public double GrossAmount { get; set; }
[Required]
[Display(Name = "Tax Amount")]
public double TaxAmount { get; set; }
[Required]
[Display(Name = "Net Amount")]
public double NetAmount { get; set; }
public int Mileage { get; set; }
[Display(Name = "Mileage Rate")]
public double MileageRate { get; set; }
[Required]
[Display(Name = "Date Submitted")]
public DateTime? DateSubmitted { get; set; }
[Required]
[Display(Name = "Expense Date")]
public DateTime? ExpenseDate { get; set; }
public string UserId { get; set; }
[ForeignKey("UserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Category == "Auto - Mileage" && Mileage == 0)
{
yield return new ValidationResult("You must enter a mileage amount if the chosen category is mileage.");
}
}
}
Controller:
public class ExpensesController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: Expenses
[Authorize]
public ActionResult Index()
{
var expenses = db.Expenses.Include(e => e.ApplicationUser);
return View(expenses.ToList());
}
// GET: Expenses/Details/5
[Authorize]
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Expense expense = db.Expenses.Find(id);
if (expense == null)
{
return HttpNotFound();
}
return View(expense);
}
// GET: Expenses/Create
[Authorize]
public ActionResult Create()
{
ViewBag.UserId = new SelectList(db.Users, "Id", "Fullname");
return View();
}
// POST: Expenses/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize]
public ActionResult Create([Bind(Include = "ID,Category,Description,GrossAmount,TaxAmount,NetAmount,Mileage,MileageRate,DateSubmitted,ExpenseDate,UserId")] Expense expense)
{
if (ModelState.IsValid)
{
db.Expenses.Add(expense);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.UserId = new SelectList(db.Users, "Id", "Fullname", expense.UserId);
return View(expense);
}
// GET: Expenses/Edit/5
[Authorize]
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Expense expense = db.Expenses.Find(id);
if (expense == null)
{
return HttpNotFound();
}
ViewBag.UserId = new SelectList(db.Users, "Id", "Fullname", expense.UserId);
return View(expense);
}
// POST: Expenses/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize]
public ActionResult Edit([Bind(Include = "ID,Category,Description,GrossAmount,TaxAmount,NetAmount,Mileage,MileageRate,DateSubmitted,ExpenseDate,UserId")] Expense expense)
{
if (ModelState.IsValid)
{
db.Entry(expense).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.UserId = new SelectList(db.Users, "Id", "Fullname", expense.UserId);
return View(expense);
}
// GET: Expenses/Delete/5
[Authorize]
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Expense expense = db.Expenses.Find(id);
if (expense == null)
{
return HttpNotFound();
}
return View(expense);
}
// POST: Expenses/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
[Authorize]
public ActionResult DeleteConfirmed(int id)
{
Expense expense = db.Expenses.Find(id);
db.Expenses.Remove(expense);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
Index.cshtml:
#model IEnumerable<PacificPetExpenses.Models.Expense>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ApplicationUser.Fullname)
</th>
<th>
#Html.DisplayNameFor(model => model.Category)
</th>
<th>
#Html.DisplayNameFor(model => model.Description)
</th>
<th>
#Html.DisplayNameFor(model => model.GrossAmount)
</th>
<th>
#Html.DisplayNameFor(model => model.TaxAmount)
</th>
<th>
#Html.DisplayNameFor(model => model.NetAmount)
</th>
<th>
#Html.DisplayNameFor(model => model.Mileage)
</th>
<th>
#Html.DisplayNameFor(model => model.MileageRate)
</th>
<th>
#Html.DisplayNameFor(model => model.DateSubmitted)
</th>
<th>
#Html.DisplayNameFor(model => model.ExpenseDate)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ApplicationUser.Fullname)
</td>
<td>
#Html.DisplayFor(modelItem => item.Category)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.GrossAmount)
</td>
<td>
#Html.DisplayFor(modelItem => item.TaxAmount)
</td>
<td>
#Html.DisplayFor(modelItem => item.NetAmount)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mileage)
</td>
<td>
#Html.DisplayFor(modelItem => item.MileageRate)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateSubmitted)
</td>
<td>
#Html.DisplayFor(modelItem => item.ExpenseDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
#Html.ActionLink("Details", "Details", new { id=item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
Please help.
Thank you.
Select your Expenses with the current user id. Like this.
// GET: Expenses
[Authorize]
public ActionResult Index()
{
var expenses = db.Expenses.Where(e => e.UserId == User.Identity.GetUserId());
return View(expenses.ToList());
}
I have found the answer. Padhraic was really close, but his answer helped me solve my problem.
In my controller, I had:
public ActionResult Index()
{
var expenses = db.Expenses.Include(e => e.ApplicationUser);
return View(expenses.ToList());
}
Instead, this should be:
public ActionResult Index()
{
string currentUserId = User.Identity.GetUserId();
var expenses = db.Expenses.Where(e => e.UserId == currentUserId);
return View(expenses.ToList());
}
According to Stephen Muecke's comment on my question, db.Expenses.Include(e => e.ApplicationUser) was returning all rows in my database. Instead I needed to filter the results to the current user.
I build alittke website using c# razor.
I have a model class named "clientModel".
I used crud operation using entity framework.
at first, evrything worked fine .
But when I changed the primary key of the clientModel class from "tracingNumber" to "emailAdress" I can't delete and edit the db from the website.
when I try to do this I get HTTP Error 404.0 - Not Found.
any idea??
controller:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using VicoProject___NewVersion.Models;
namespace Project___NewVersion.Controllers
{
public class ClientController : Controller
{
private ClientModelsDBContext db = new ClientModelsDBContext();
//
// GET: /Model/
public ActionResult Index()
{
return View(db.Clients.ToList());
}
//
// GET: /Model/Details/5
public ActionResult Details(int id = 0)
{
ClientModels clientmodels = db.Clients.Find(id);
if (clientmodels == null)
{
return HttpNotFound();
}
return View(clientmodels);
}
//
// GET: /Model/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Model/Create
[HttpPost]
public ActionResult Create(ClientModels clientmodels)
{
if (ModelState.IsValid)
{
db.Clients.Add(clientmodels);
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View(clientmodels);
}
//
// GET: /Model/Edit/5
public ActionResult Edit(int id = 0)
{
ClientModels clientmodels = db.Clients.Find(id);
if (clientmodels == null)
{
return HttpNotFound();
}
return View(clientmodels);
}
//
// POST: /Model/Edit/5
[HttpPost]
public ActionResult Edit(ClientModels clientmodels)
{
if (ModelState.IsValid)
{
db.Entry(clientmodels).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(clientmodels);
}
//
// GET: /Model/Delete/5
public ActionResult Delete(int id = 0)
{
ClientModels clientmodels = db.Clients.Find(id);
if (clientmodels == null)
{
return HttpNotFound();
}
return View(clientmodels);
}
//
// POST: /Model/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
ClientModels clientmodels = db.Clients.Find(id);
db.Clients.Remove(clientmodels);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
public ActionResult Search(string search)
{
var r = db.Clients.Where(t => t.emailAdress.Contains(search) || t.name.Contains(search)).ToList();
Console.Write(r);
return RedirectToAction("Search");
}
}
}
client model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
namespace Project___NewVersion.Models
{
public class ClientModels
{
[Required]
public string name { get; set;}
[Required]
[MaxLength(10, ErrorMessage = "Phone Number must be 10 numbers") , MinLength(10, ErrorMessage = "Phone Number must be 10 numbers")]
[DataType(DataType.PhoneNumber, ErrorMessage = "Invalid Phone Number")]
public String phoneNumber { get; set; }
[Key]
[Required]
[DataType(DataType.EmailAddress, ErrorMessage = "Invalid Email Address")]
public string emailAdress { get; set; }
}
public class ClientModelsDBContext : DbContext
{
static ClientModelsDBContext()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<ClientModelsDBContext>());
}
public DbSet<ClientModels> Clients { get; set; }
}
}
the client/index view:
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.name)
</th>
<th>
#Html.DisplayNameFor(model => model.phoneNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.emailAdress)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)
</td>
<td>
#Html.DisplayFor(modelItem => item.phoneNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.emailAdress)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.emailAdress }) |
#Html.ActionLink("Details", "Details", new { id=item.emailAdress }) |
#Html.ActionLink("Delete", "Delete", new { id=item.emailAdress})
</td>
</tr>
}
</table>
The function with the signature
public ActionResult Delete(int id = 0)
needs to be called. The parameter to this is an int. I assume since changing it the id is now a string - so the framework doesn't know which method to call.