How to display all rows with same ID in ASP.NET MVC? - c#

My Index page displays all rows from an Azure SQL Database. When I click a row I get redirected to a unique URL with a QR code for that URL and it also displays the data for only that row. Each row has it's own unique ID, but also a truckID. The truckID is for a driver who can "own" several rows of data, so I want to show every row with the same truckID after a row is clicked.
This is what I've got so far:
MODEL
namespace QR
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("data")]
public partial class data
{
[Required]
[StringLength(50)]
public string Contract { get; set; }
[StringLength(50)]
public string Sort { get; set; }
public int? Report { get; set; }
public double? InputKG { get; set; }
public double? OutputKG { get; set; }
public double? Recovery { get; set; }
public double? Si { get; set; }
public double? Cu { get; set; }
public double? Mn { get; set; }
public double? Mg { get; set; }
public double? Zn { get; set; }
public double? Cr { get; set; }
public double? Fe { get; set; }
public double? Pb { get; set; }
public int? truckID { get; set; }
[Key]
public int ID{ get; set; }
}
}
VIEW (after a row is clicked from Index)
#model QR.data
#{
ViewBag.Title = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>QR code</h2>
<img src="/Home/BarcodeImage?barcodeText=#Request.Url.OriginalString"/>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Contract)
</th>
<th>
#Html.DisplayNameFor(model => model.Sort)
</th>
<th>
#Html.DisplayNameFor(model => model.Report)
</th>
<th>
#Html.DisplayNameFor(model => model.InputKG)
</th>
<th>
#Html.DisplayNameFor(model => model.OutputKG)
</th>
<th>
#Html.DisplayNameFor(model => model.Recovery)
</th>
<th>
#Html.DisplayNameFor(model => model.Si)
</th>
<th>
#Html.DisplayNameFor(model => model.Cu)
</th>
<th>
#Html.DisplayNameFor(model => model.Mn)
</th>
<th>
#Html.DisplayNameFor(model => model.Mg)
</th>
<th>
#Html.DisplayNameFor(model => model.Zn)
</th>
<th>
#Html.DisplayNameFor(model => model.Cr)
</th>
<th>
#Html.DisplayNameFor(model => model.Fe)
</th>
<th>
#Html.DisplayNameFor(model => model.Pb)
</th>
</tr>
<tr>
<td>
#Html.DisplayFor(model => model.Contract)
</td>
<td>
#Html.DisplayFor(model => model.Sort)
</td>
<td>
#Html.DisplayFor(model => model.Report)
</td>
<td>
#Html.DisplayFor(model => model.InputKG)
</td>
<td>
#Html.DisplayFor(model => model.OutputKG)
</td>
<td>
#Html.DisplayFor(model => model.Recovery)
</td>
<td>
#Html.DisplayFor(model => model.Si)
</td>
<td>
#Html.DisplayFor(model => model.Cu)
</td>
<td>
#Html.DisplayFor(model => model.Mn)
</td>
<td>
#Html.DisplayFor(model => model.Mg)
</td>
<td>
#Html.DisplayFor(model => model.Zn)
</td>
<td>
#Html.DisplayFor(model => model.Cr)
</td>
<td>
#Html.DisplayFor(model => model.Fe)
</td>
<td>
#Html.DisplayFor(model => model.Pb)
</td>
</tr>
</table>
<p>
#Html.ActionLink("Back to List", "Index")
</p>
CONTROLLER
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
data data= db.data.Find(id);
if (data == null)
{
return HttpNotFound();
}
return View(data);
}
And on the Index I have this link:
#Html.ActionLink("QR", "Details", new { id = item.ID})
Help?

With this answer I presume two things:
db is a DbContext and has a property called data which is a DbSet<data>
You don't have any other models for your data, only the data class
If the above is true, here's what you should do:
In the controller:
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
data data = db.data.Find(id);
if (data == null)
{
return HttpNotFound();
}
var groupedData = db.data.Where(d => d.truckID == data.truckID).ToList();
return View(groupedData);
}
In your view (Details)
// This is after declaring the table headers
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(model => item.Contract)
</td>
// Fill in rest of the td rows as you did
<td>
#Html.DisplayFor(model => item.Pb)
</td>
</tr>
}
This should display all of the rows correctly.
Also, this is just for readability, but it is really important, capitalize your class names, i.e. it should be public partial class Data not data.

You didn't get any error on this statement ?
data data= db.data.Find(id);
I think it has to be like this
data data= db.data.Find(i=>i.ID == id);
and I supposed you were using foreach loop to print all of the data and in that loop you have that #Html.ActionLink.

Related

how to fix duplicate Displayed records in table in ASP.NET Core MVC?

I'm trying to display records to View but it shows duplicate records. I try to debug in the Controller, the records are correctly retrieved from the database no prob The problem is in the Views.
<tbody>
#if (Model == null)
{
<tr>
<td colspan="7" class="text-center">No Model Data</td>
</tr>
}
else
{
#foreach (var list in Model)
{
<tr>
<td>#Html.DisplayFor(Model => list.EmployeeID)</td>
<td>#Html.DisplayFor(Model => list.EmployeeName)</td>
<td>#Html.DisplayFor(Model => list.Address)</td>
<td>#Html.DisplayFor(Model => list.Email)</td>
<td>#Html.DisplayFor(Model => list.ContactNo)</td>
<td>#Html.DisplayFor(Model => list.Gender)</td>
<td>#Html.DisplayFor(Model => list.Birthday)</td>
<td>#Html.DisplayFor(Model => list.Status)</td>
<td>#Html.DisplayFor(Model => list.Position)</td>
<td>#Html.DisplayFor(Model => list.Department)</td>
<td>
<button class="btn-default" asp-action="Update" asp-route-id="#list.EmployeeID">Edit</button>
</td>
<td>
<form asp-action="Delete" method="post" asp-route-id="#list.EmployeeID">
<button class="btn-danger">Delete</button>
</form>
</td>
</tr>
}
}
</tbody>
Employee.cs
public class Employee
{
public string EmployeeID { get; set; }
public string EmployeeName { get; set; }
public string Address { get; set; }
public string Email { get; set; }
public string ContactNo { get; set; }
public string Gender { get; set; }
public DateTime? Birthday { get; set; }
public string Status { get; set; }
public string Position { get; set; }
public string Department { get; set; }
}
HomeController.cs
public class HomeController : Controller
{
public IActionResult Employees()
{
var list = new List<Employee>
{
new Employee
{
EmployeeID = "EmployeeID",
Address = "Address",
Birthday = DateTime.Now,
ContactNo = "ContactNo",
Department = "Department",
Email = "Email",
EmployeeName = "EmployeeName",
Gender = "Gender",
Position = "Position",
Status = "Status"
},
new Employee
{
EmployeeID = "EmployeeID2",
Address = "Address",
Birthday = DateTime.Now,
ContactNo = "ContactNo",
Department = "Department",
Email = "Email",
EmployeeName = "EmployeeName",
Gender = "Gender",
Position = "Position",
Status = "Status"
}
};
return View(list);
}
}
Employees.cshtml
#model IEnumerable<WebApplication6.Controllers.Employee>
#{
ViewData["Title"] = "Employees";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Employees</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.EmployeeID)
</th>
<th>
#Html.DisplayNameFor(model => model.EmployeeName)
</th>
<th>
#Html.DisplayNameFor(model => model.Address)
</th>
<th>
#Html.DisplayNameFor(model => model.Email)
</th>
<th>
#Html.DisplayNameFor(model => model.ContactNo)
</th>
<th>
#Html.DisplayNameFor(model => model.Gender)
</th>
<th>
#Html.DisplayNameFor(model => model.Birthday)
</th>
<th>
#Html.DisplayNameFor(model => model.Status)
</th>
<th>
#Html.DisplayNameFor(model => model.Position)
</th>
<th>
#Html.DisplayNameFor(model => model.Department)
</th>
<th></th>
</tr>
</thead>
<tbody>
#if (Model == null)
{
<tr>
<td colspan="7" class="text-center">No Model Data</td>
</tr>
}
else
{
foreach (var list in Model)
{
<tr>
<td>#Html.DisplayFor(Model => list.EmployeeID)</td>
<td>#Html.DisplayFor(Model => list.EmployeeName)</td>
<td>#Html.DisplayFor(Model => list.Address)</td>
<td>#Html.DisplayFor(Model => list.Email)</td>
<td>#Html.DisplayFor(Model => list.ContactNo)</td>
<td>#Html.DisplayFor(Model => list.Gender)</td>
<td>#Html.DisplayFor(Model => list.Birthday)</td>
<td>#Html.DisplayFor(Model => list.Status)</td>
<td>#Html.DisplayFor(Model => list.Position)</td>
<td>#Html.DisplayFor(Model => list.Department)</td>
<td>
<button class="btn-default" asp-action="Update" asp-route-id="#list.EmployeeID">Edit</button>
</td>
<td>
<form asp-action="Delete" method="post" asp-route-id="#list.EmployeeID">
<button class="btn-danger">Delete</button>
</form>
</td>
</tr>
}
}
</tbody>
</table>
It all works for me.
Result image:
/home/employees
What does your data look like if you select them in database?
I experienced what I believe was a similar issue.
I believe the cause of the problem is how Visual Studio was reading the definition of the SQL Server view -- specifically the combination of columns that were identified as "Entity Keys". I think Visual Studio simply finds all columns that are NOT NULL and sets them as Entity Keys.
In my case, I had a fairly complex SQL Server view (with multiple CTEs, a CROSS APPLY join, an EXCEPT sub-query, a UNION, and a couple LEFT OUTER JOINS). This complex SQL Server view does return accurate data. However, in the SQL Server view definition, some columns were defined as NULL when (logically) they will never actually be NULL. I had to force the SQL Server view column definitions to be NOT NULL. I had to use the SQL IsNull function. For example: SELECT ISNULL(col1,'') AS col1...
I then dropped and re-added the SQL Server view to the Visual Studio entity framework model and verified the proper columns were marked as entity keys.
This fixed my problem.

Get the Child Class Propert in Parent class

I had a two controllers in my application with database first approach
SampCutReqMaster.CS
public partial class SampCutReqMaster
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public SampCutReqMaster()
{
this.SamCutAssignmentMasters = new HashSet<SamCutAssignmentMaster>();
}
public decimal SampCutreqID { get; set; }
public Nullable<decimal> BuyerID { get; set; }
public Nullable<decimal> PatternRefID { get; set; }
public Nullable<decimal> PatternStyleID { get; set; }
public Nullable<decimal> SampleTypeID { get; set; }
public virtual BuyerMaster BuyerMaster { get; set; }
public virtual PatternStyle PatternStyle { get; set; }
public virtual PatterRefMaster PatterRefMaster { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<SamCutAssignmentMaster> SamCutAssignmentMasters { get; set; }
public virtual SampleType SampleType { get; set; }
}
and The next is
SamCutAssignmentMaster
public partial class SamCutAssignmentMaster
{
public decimal CutAssignID { get; set; }
public decimal SampCutreqID { get; set; }
public System.DateTime ReceivedDate { get; set; }
public string ReceivedBy { get; set; }
public Nullable<decimal> PatternMasterID { get; set; }
public virtual PatternMaster PatternMaster { get; set; }
public virtual SampCutReqMaster SampCutReqMaster { get; set; }
}
I had created a controller with a index view for SampCutReqMaster
public class SampCutReqMastersController : Controller
{
private ArtEntities db = new ArtEntities();
// GET: SampCutReqMasters
public ActionResult Index()
{
var sampCutReqMasters = db.SampCutReqMasters.Include(s => s.BuyerMaster).Include(s => s.PatternStyle).Include(s => s.PatterRefMaster).Include(s => s.SampleType).Include(s=>s.SamCutAssignmentMasters);
var sampCutReqMasterssort = sampCutReqMasters.ToList().OrderByDescending(a => a.AddedDate);
return View(sampCutReqMasterssort.ToList());
}
}
I want to get the "receivedBy" of SamcutAssignmentMaster(child class) in my view of SamCutReqMaster (Parent).But there may be no data in SamcutAssignmentMaster relavant to SamCutReqMaster (FK is SamCutReqID)
In Index view Below I need to access SamcutAssignmentMaster.receivedBy
#model IEnumerable<WebArtSampler.Models.SampCutReqMaster>
#{
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.ReqNum)
</th>
<th>
#Html.DisplayNameFor(model => model.Fabric)
</th>
<th>
#Html.DisplayNameFor(model => model.SampleRequiredDate)
</th>
<th>
#Html.DisplayNameFor(model => model.AddedDate)
</th>
<th>
#Html.DisplayNameFor(model => model.AddedBy)
</th>
<th>
#Html.DisplayNameFor(model => model.BuyerMaster.BuyerName)
</th>
<th>
#Html.DisplayNameFor(model => model.PatternStyle.StyleName)
</th>
<th>
#Html.DisplayNameFor(model => model.PatterRefMaster.PatterRefNum)
</th>
<th>
#Html.DisplayNameFor(model => model.SampleType.SampleType1)
</th>
<th>
#Html.DisplayNameFor(model => model.SizeDetail)
</th>
<th>
#Html.DisplayNameFor(model => model.Qty)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ReqNum)
</td>
<td>
#Html.DisplayFor(modelItem => item.Fabric)
</td>
<td>
#Html.DisplayFor(modelItem => item.SampleRequiredDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.AddedDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.AddedBy)
</td>
<td>
#Html.DisplayFor(modelItem => item.BuyerMaster.BuyerName)
</td>
<td>
#Html.DisplayFor(modelItem => item.PatternStyle.StyleName)
</td>
<td>
#Html.DisplayFor(modelItem => item.PatterRefMaster.PatterRefNum)
</td>
<td>
#Html.DisplayFor(modelItem => item.SampleType.SampleType1)
</td>
<td>
#Html.DisplayFor(modelItem => item.SizeDetail)
</td>
<td>
#Html.DisplayFor(modelItem => item.Qty)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.SampCutreqID }) |
#Html.ActionLink("Details", "Details", new { id=item.SampCutreqID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.SampCutreqID })
</td>
</tr>
}
</table>
Ok. You can't access the properties whilst your type is still as the interface ICollection. You need to cast it to a concrete type before you can access the properties of the collection via an index.
#for (var adCounter = 0; adCounter <= (Model.SamCutAssignmentMasters.Count - 1); adCounter++)
{
#Html.DisplayFor(x => ((List<SamCutAssignmentMaster>)x.SamCutAssignmentMasters)[adCounter].ReceivedBy)
}
Cast the type to a list as per the above and you should see the properties.
NOTE: You are using DisplayFor in your view. If you intend to post the contents of this view the model will not bind unless you have a hidden control for each item or you switch to TextBoxFor. You will also need the for (Counter) syntax as well to bind to items in collections.
Hope that helps.

Filtering by parameter & Routing

I have an MachineInfo view page which I am showing 60 different specifications of the related machine like processor info, ram info, disk info, db info etc.
ActionLink to this page is:
#Html.ActionLink("Machine Info", "MachineInfo", new { id = Model.LicenseKey }) |
Controller:
public ActionResult MachineInfo(string LicenseKey)
{
if (LicenseKey == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Farm farm = db.Farms.Find(LicenseKey);
if (farm == null)
{
return HttpNotFound();
}
return View(farm);
}
Farm Model:
public partial class Farm
{
public Farm()
{
this.FarmChanges = new HashSet<FarmChange>();
this.FarmDetails = new HashSet<FarmDetail>();
this.FarmTables = new HashSet<FarmTable>();
}
public int Id { get; set; }
public string LicenseKey { get; set; }
public string Name { get; set; }
public string CustomerName { get; set; }
public virtual ICollection<FarmChange> FarmChanges { get; set; }
public virtual ICollection<FarmDetail> FarmDetails { get; set; }
public virtual ICollection<FarmTable> FarmTables { get; set; }
}
FarmDetails Model:
public partial class FarmDetail
{
public System.Guid Id { get; set; }
public int FarmId { get; set; }
public int Type { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public virtual Farm Farm { get; set; }
}
All the MachineInfo is coming from the "Value" in the FarmDetails table.
View:
#model IEnumerable<FarmManagement.Models.FarmDetail>
#{
ViewBag.Title = "Machine Info";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Machine Info</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Type)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Value)
</th>
<th>
#Html.DisplayNameFor(model => model.Farm.LicenseKey)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Type)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Value)
</td>
<td>
#Html.DisplayFor(modelItem => item.Farm.LicenseKey)
</td>
<td>
</td>
</tr>
}
</table>
#Html.ActionLink("Back to Farms List", "Index")
I am trying to show MachineInfo of a specific machine (LicenseKey=ABXYZ-XYZAB) with this url: mydomain.com/MachineInfo/ABXYZ-XYZAB
I need to filter the view by LicenseKey.
After my all tries, I'm only getting 400 - Bad Request error (Because LicenseKey == null) or getting the MachineInfo of ALL machines, not the specific machine with LicenseKey=ABXYZ-XYZAB.
What I am doing wrong?
Change your actionlink code
#Html.ActionLink("Machine Info", "MachineInfo", new { id = Model.LicenseKey })
to
#Html.ActionLink("Machine Info", "MachineInfo", new { LicenseKey = Model.LicenseKey })
As the Action link parameter name should match with the controller action parameter name.
Solved the problem after making following changes:
New Controller After Change:
public ActionResult MachineInfo(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
FarmDetail farmdetail = db.FarmDetails.Where(x => x.FarmId == id).FirstOrDefault();
if (farmdetail == null)
{
return HttpNotFound();
}
return View(farmdetail);
}
New View After Change:
#model FarmManagement.Models.FarmDetail
#{
ViewBag.Title = "Machine Info";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Machine Info</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Type)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Value)
</th>
<th>
#Html.DisplayNameFor(model => model.Farm.LicenseKey)
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Farm.FarmDetails.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(model => model.Farm.FarmDetails.ElementAt(i).Type)
</td>
<td>
#Html.DisplayFor(model => model.Farm.FarmDetails.ElementAt(i).Name)
</td>
<td>
#Html.DisplayFor(model => model.Farm.FarmDetails.ElementAt(i).Value)
</td>
<td>
#Html.DisplayFor(model => model.Farm.LicenseKey)
</td>
<td>
</tr>
}
</table>
#Html.ActionLink("Back to Farms List", "Index")
I needed to use a where sentence in Controller;
FarmDetail farmdetail = db.FarmDetails.Where(x => x.FarmId == id).FirstOrDefault();
And removed IEnumerable from the View and changed #foreach to #for with ElementAt(i).
#Html.DisplayFor(model => model.Farm.FarmDetails.ElementAt(i).Name)

Enable boolean and enter text in view then pass back to controller - MVC

I have a view that displays a boolean (currently defaulted to 0) in a box format in the view that I cannot check to activate as true and also want to enter text in the result field to pass back to the controller and save both changes to a table. Can someone please explain what I have to do to allow this functionality to work please.
Controller code
public ActionResult P1A1Mark()
{
List<MarkModel> query = (from row in db.submits
where row.assignment_no.Equals("1") && row.group_no == 1
group row by new { row.assignment_no, row.student_no, row.student.firstname, row.student.surname } into g
select new MarkModel
{
student_no = g.Key.student_no,
student_surname = g.Key.surname,
student_firstname = g.Key.firstname
}
).ToList();
return View(query);
}
View
#model IEnumerable<MvcApplication2.Models.MarkModel>
#{
ViewBag.Title = "P1A1Mark";
}
<h2>Mark Student Assignments</h2>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.student_no)
</th>
<th>
#Html.DisplayNameFor(model => model.student_surname)
</th>
<th>
#Html.DisplayNameFor(model => model.student_firstname)
</th>
<th>
#Html.DisplayNameFor(model => model.submitted)
</th>
<th>
#Html.DisplayNameFor(model => model.result)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.student_no)
</td>
<td>
#Html.DisplayFor(modelItem => item.student_surname)
</td>
<td>
#Html.DisplayFor(modelItem => item.student_firstname)
</td>
<td>
#Html.DisplayFor(modelItem => item.submitted)
</td>
<td>
#Html.DisplayFor(modelItem => item.result)
</td>
</tr>
}
</table>
Model
public class MarkModel
{
public string student_no { get; set; }
public string student_surname { get; set; }
public string student_firstname { get; set; }
public string assignment_no { get; set; }
public bool submitted { get; set; }
public string result { get; set; }
public Nullable<int> group_no { get; set; }
}
Create an EditorTemplate for type of MarkModel.
In /Views/Shared/EditorTemplates/MarkModel.cshtml
#model MvcApplication2.Models.MarkModel
<tr>
<td>#Html.DisplayFor(m => m.student_no)</td>
<td>#Html.DisplayFor(m => m.student_surname)</td>
<td>#Html.DisplayFor(m => m.student_firstname)</td>
<td>#Html.CheckBoxFor(m => m.submitted)</td>
<td>#Html.TextBoxFor(m => m.result)</td>
</tr>
and in the main view
#model IEnumerable<MvcApplication2.Models.MarkModel>
#using (Html.BeginForm())
{
<table>
<thead>
// add your th elements
</thead>
<tbody>
#Html.EditorFor(m => m)
<tbody>
</table>
<input type="submit" ../>
}
and create a method to post back to
[HttpPost]
public ActionResult P1A1Mark(IEnumerable<MarkModel>model)
Alternatively you can use a for loop in the view (the model must be IList<T>)
for(int i = 0; i < Model.Count; i++)
{
....
#Html.CheckBoxFor(m => m[i].submitted)
}

Enumerated list of child class not working

I am creating a webpage for a help desk software where the top shows the information from the ticket class and then the bottom for the ticketNotes that are attached to the ticket class through an ICollection. Currently if I comment out the bottom, the top portion (the static table) works correctly. However, the bottom two tables that point to the ICollection are not working. Here is the error that I am getting:
Here is my view:
#model HelpDesk.Model.Ticket
#{
ViewBag.Title = "Ticket# " + Html.DisplayFor(model => model.TicketNumber);
}
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.CategoryId)
</th>
<th>
#Html.DisplayFor(model => model.Category.CategoryName)
</th>
</tr>
<tr>
<th>
#Html.DisplayNameFor(model => model.OpenUserId)
</th>
<th>
#Html.DisplayFor(model => model.OpenUser.FullName)
</th>
</tr>
<tr>
<th>
#Html.DisplayNameFor(model => model.OpenDate)
</th>
<th>
#Html.DisplayFor(model => model.OpenDate)
</th>
</tr>
<tr>
<th>
#Html.DisplayNameFor(model => model.TechnicianId)
</th>
<th>
#Html.DisplayFor(model => model.Technician.FullName)
</th>
</tr>
<tr>
<th>
#Html.DisplayNameFor(model => model.TicketStatusId)
</th>
<th>
#Html.DisplayFor(model => model.TicketStatus.StatusDescription)
</th>
</tr>
<tr>
<th>
#Html.DisplayNameFor(model => model.CloseDate)
</th>
<th>
#Html.DisplayFor(model => model.CloseDate)
</th>
</tr>
<tr></tr>
</table>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.TicketNotes.Note)
</th>
<th>
#Html.DisplayNameFor(model => model.TicketNotes.TicketNoteDate)
</th>
<th>
#Html.DisplayNameFor(model => model.TicketNotes.UserNote.FullName)
</th>
<th></th>
</tr>
#foreach (var item in Model.TicketNotes)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.TicketNotes.Note)
</td>
<td>
#Html.DisplayFor(modelItem => item.TicketNotes.TicketNoteDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.TicketNotes.UserNote.FullName)
</td>
</tr>
}
</table>
Here is my controller Code:
public ActionResult EditUserTicket(Guid id)
{
Ticket ticket = tickets.GetById(id);
var model = db.Tickets
.Include(t => t.TicketNotes)
.Where(t => t.TicketId == id).First();
return View(model);
}
and here is my Model:
namespace HelpDesk.Model
{
public class Ticket
{
public Ticket()
{
this.TicketNotes = new HashSet<TicketNote>();
}
public Guid TicketId { get; set; }
[Display(Name = "#")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
public int TicketNumber { get; set; }
[ForeignKey("Category")]
[Required]
public Guid CategoryId { get; set; }
public virtual Category Category { get; set; }
[ForeignKey("OpenUser")]
[Required]
public Guid OpenUserId { get; set; }
[Display(Name = "Ticket Owner")]
public virtual User OpenUser { get; set; }
[Display(Name = "Opened")]
[DataType(DataType.Date)]
[Required]
public DateTime OpenDate { get; set; }
[ForeignKey("Technician")]
[Required]
public Guid TechnicianId { get; set; }
[Display(Name = "Technician")]
public virtual User Technician { get; set; }
[ForeignKey("TicketStatus")]
[Required]
public Guid TicketStatusId { get; set; }
public virtual TicketStatus TicketStatus { get; set; }
[Display(Name = "Closed")]
[DataType(DataType.Date)]
public Nullable<DateTime> CloseDate { get; set; }
[Display(Name = "Note")]
public virtual ICollection<TicketNote> TicketNotes { get; set; }
//public virtual ICollection<TicketSubscription> TicketSubscriptions { get; set; }
}
}
In your foreach loop
#foreach (var item in Model.TicketNotes)
item is already an instance of TicketNote, so
#Html.DisplayFor(modelItem => item.TicketNotes.Note)
fails because TicketNote does not have a property named TicketNotes
It should be just
#Html.DisplayFor(m => item.Note)
For the table headings, you can use
#Html.DisplayNameFor(model => model.TicketNotes[0].Note)

Categories