ASP.NET MVC how to display associative data based on id's - c#

I'm trying to display data on my index view from from my models that are associated with each other based on id's. I.e. display client name, asset name that belongs to this client, and address of this client, etc...
Here's my model:
Client model:
public class Client : Person {
public ICollection<OccupancyHistoryRecord> OccupancyRecords { get; set; }
public ICollection<RentHistoryRecord> RentRecords { get; set; }
}
Asset model:
public class Asset {
public int Id { get; set; }
[Display(Name = "Asset Name")]
public string Name { get; set; }
[Display(Name = "Asset Type")]
public string Type { get; set; }
public FullAddress Address { get; set; }
[Display(Name = "Asking Rent")]
public string AskingRent { get; set; }
public ICollection<OccupancyHistoryRecord> OccupancyRecords;
public ICollection<RentHistoryRecord> RentRecords;
}
Occupancy Record:
public class OccupancyHistoryRecord {
public int Id { get; set; }
public int AssetId { get; set; }
public int ClientId { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
}
Client Controller:
public ActionResult Index()
{
var clients = db.Clients.Include(c => c.OccupancyRecords) // how to get the asset name instead of the id)
.Include(c => c.HomeAddress)
.Include(c => c.WorkAddress);
return View(clients.ToList());
}
Index View:
#model IEnumerable<RentalManagement.Models.Client>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.OccupancyRecords)
</th>
<th>
#Html.DisplayNameFor(model => model.HomeAddress)
</th>
<th>
#Html.DisplayNameFor(model => model.WorkAddress)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.OccupancyRecords)
</td>
<td>
#Html.DisplayFor(modelItem => item.HomeAddress.StreetAddress)
</td>
<td>
#Html.DisplayFor(modelItem => item.WorkAddress.StreetAddress)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Id }, null) |
#Html.ActionLink("Assets", "Details", "Assets", new { id = item.Id}, null) |
#Html.ActionLink("Details", "Details", new { id=item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
Right now it's displaying the occupancy record's Id. What I want is to display the asset name based on the occupancy's AssetId.
Thanks.

You need to change your :
public ActionResult Index()
{
var clients = db.Clients.Include(c => c.OccupancyRecords) // how to get the asset name instead of the id)
.Include(c => c.HomeAddress)
.Include(c => c.WorkAddress);
return View(clients.ToList());
}
code as below:
public ActionResult Index()
{
var clients = db.Clients.Include(c => c.OccupancyRecords.Select(s => new { AssetId = s.AssetId, AssetName = /* Find AssetName By Id here */ }))
.Include(c => c.HomeAddress)
.Include(c => c.WorkAddress);
return View(clients.ToList());
}

Related

What properties do i have to give my controller index method?

I am building a project for school. I am almost there but there is one error I can't fix.
I am making a bike reservation asp.net website.
The error says I pass a list to the index page of reservations and it expects an IEnumerable.
I already tried making the expected a list, but that also gives an error.
I have seen other fixes of this problem, but I can't get it to work.
Here is my original index method.
// GET: Reservations
public ActionResult Index()
{
var reservations = db.Reservations.Include(r => r.Bike).Include(r => r.Customer).Include(r => r.DropoffStore).Include(r => r.PickupStore);
return View(reservations.ToList());
}
Here is my new Controller index method that i got from someone else, but i dont know why i wont work:
// GET: Reservations
public ActionResult Index()
{
var reservations = db.Reservations.Include(r => r.Bike).Include(r => r.Customer).Include(r => r.DropoffStore).Include(r => r.PickupStore);
IEnumerable<ReservationViewModel> reservationViewModels = new List<ReservationViewModel>();
foreach (var reservation in reservations)
{
var reservationViewModel = new ReservationViewModel
{
(PROPERTY)
};
reservationViewModels.ToList().Add(reservationViewModel);
}
return View(reservationViewModels);
}
Here is my index page:
#model IEnumerable<ASP.NET_Framwork_for_real_bitch.ViewModels.ReservationViewModel>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Reservation.Customer.FirstName)
</th>
<th>
#Html.DisplayNameFor(model => model.Reservation.Customer.LastName)
</th>
<th>
#Html.DisplayNameFor(model => model.Reservation.Customer.Email)
</th>
<th>
#Html.DisplayNameFor(model => model.Reservation.Customer.Gender)
</th>
<th>
#Html.DisplayNameFor(model => model.Reservation.DropoffStore_Id)
</th>
<th>
#Html.DisplayNameFor(model => model.Reservation.PickupStore_Id)
</th>
<th>
#Html.DisplayNameFor(model => model.Reservation.StartDate)
</th>
<th>
#Html.DisplayNameFor(model => model.Reservation.EndDate)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Reservation.Customer.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Reservation.Customer.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Reservation.Customer.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.Reservation.Customer.Gender)
</td>
<td>
#Html.DisplayFor(modelItem => item.Reservation.DropoffStore.StoreName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Reservation.PickupStore.StoreName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Reservation.StartDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Reservation.EndDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Reservation.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Reservation.Id })
</td>
</tr>
}
</table>
This is the exact error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[ASP.NET_Framwork_for_real_bitch.Models.Reservation]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[ASP.NET_Framwork_for_real_bitch.ViewModels.ReservationViewModel]'.
my Whole ReservationViewModel:
using ASP.NET_Framwork_for_real_bitch.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ASP.NET_Framwork_for_real_bitch.ViewModels
{
public class ReservationViewModel
{
private BikeShoppaModel db = new BikeShoppaModel();
public Reservation Reservation { get; set; }
public SelectList DropoffStore_Id { get; private set; }
public SelectList PickupStore_Id { get; private set; }
public SelectList Bikes { get; private set; }
public SelectList CustomerGender { get; set; }
public int TotalDays { get; set; }
public double TotalPrice { get; set; }
public ReservationViewModel()
{
DropoffStore_Id = new SelectList(db.Stores, "Id", "StoreName");
PickupStore_Id = new SelectList(db.Stores, "Id", "StoreName");
Bikes = new SelectList(db.Bikes, "Id", "Brand");
CustomerGender = new SelectList(db.Customers, "Id", "Gender");
}
public ReservationViewModel(int id) : this()
{
Reservation = db.Reservations.Find(id);
TotalDays = (Reservation.EndDate.Date - Reservation.StartDate.Date).Days + 1;
}
public void Save()
{
if(Reservation.Id > 0)
{
db.Entry(Reservation).State = EntityState.Modified;
}
else
{
db.Reservations.Add(Reservation);
}
db.SaveChanges();
}
}
}
my Reservations model:
public class Reservation
{
public int Id { get; set; }
[ForeignKey("Customer")]
[Display(Name = "Customer")]
public int Customer_Id { get; set; }
public virtual Customer Customer { get; set; }
[ForeignKey("Bike")]
public int Bike_Id { get; set; }
public Bike Bike { get; set; }
[DataType(DataType.Date)]
[Column(TypeName = "Date")]
[Display(Name = "Start date")]
public DateTime StartDate { get; set; }
[DataType(DataType.Date)]
[Column(TypeName = "Date")]
[Display(Name = "End date")]
public DateTime EndDate { get; set; }
[ForeignKey("PickupStore")]
[Display(Name = "Pickup store")]
public int PickupStore_Id { get; set; }
public Store PickupStore { get; set; }
[ForeignKey("DropoffStore")]
[Display(Name = "Dropoff store")]
public int DropoffStore_Id { get; set; }
public Store DropoffStore { get; set; }
}

MVC Model is null in view HTTPGET [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
I have been messing around to find a solution as on of my view which is created using add view from respective action in List Template is giving an exception of System.NullReferenceException: Object reference not set to an instance of an object.
Line 45: </tr>
Line 46:
Line 47: #foreach (var item in Model) {
Line 48: <tr>
Line 49: <td>
Here is my Controller Function
public ActionResult ViewCarpets()
{
IEnumerable<SelectListItem> Qualities = context.Qualities.Select(c => new SelectListItem
{
Value = c.Quality_Id.ToString(),
Text = c.QName
});
IEnumerable<SelectListItem> Suppliers = context.Suppliers.Select(c => new SelectListItem
{
Value = c.Supplier_Id.ToString(),
Text = c.SName
});
IEnumerable<SelectListItem> Designs = context.Design.Select(c => new SelectListItem
{
Value = c.Design_Id.ToString(),
Text = c.DName
});
ViewBag.Quality_Id = Qualities;
ViewBag.Supplier_Id = Suppliers;
ViewBag.Design_Id = Designs;
return View("ViewCarpets");
}
Here is my View
#model IEnumerable<SOC.Models.Product>
#{
ViewBag.Title = "ViewCarpets";
}
<h2>View Carpets</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Design.DName)
</th>
<th>
#Html.DisplayNameFor(model => model.Quality.QName)
</th>
<th>
#Html.DisplayNameFor(model => model.Supplier.SName)
</th>
<th>
#Html.DisplayNameFor(model => model.PColor)
</th>
<th>
#Html.DisplayNameFor(model => model.PBorder_Color)
</th>
<th>
#Html.DisplayNameFor(model => model.PSKU)
</th>
<th>
#Html.DisplayNameFor(model => model.PLength)
</th>
<th>
#Html.DisplayNameFor(model => model.PWidth)
</th>
<th>
#Html.DisplayNameFor(model => model.PCost)
</th>
<th>
#Html.DisplayNameFor(model => model.IsSold)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Design.DName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Quality.QName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Supplier.SName)
</td>
<td>
#Html.DisplayFor(modelItem => item.PColor)
</td>
<td>
#Html.DisplayFor(modelItem => item.PBorder_Color)
</td>
<td>
#Html.DisplayFor(modelItem => item.PSKU)
</td>
<td>
#Html.DisplayFor(modelItem => item.PLength)
</td>
<td>
#Html.DisplayFor(modelItem => item.PWidth)
</td>
<td>
#Html.DisplayFor(modelItem => item.PCost)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsSold)
</td>
<td>
#Html.ActionLink("Edit", "EditCarpet", new { id = item.Product_Id }) |
#Html.ActionLink("Details", "CarpetDetails", new { id = item.Product_Id }) |
#Html.ActionLink("Delete", "DeleteCarpet", new { id = item.Product_Id })
</td>
</tr>
}
</table>
and Finally Model
namespace SOC.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("Product")]
public partial class Product
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Product()
{
Order_Details = new HashSet<Order_Details>();
}
public Product(Product product)
{
this.Quality_Id = product.Quality_Id;
this.Design_Id = product.Design_Id;
this.Supplier_Id = product.Supplier_Id;
this.PColor = product.PColor;
this.PBorder_Color = product.PBorder_Color;
this.PSKU = product.PSKU;
this.PLength = product.PLength;
this.PWidth = product.PWidth;
this.IsSold = product.IsSold;
}
[Key]
public int Product_Id { get; set; }
[Display(Name="Quality")]
public int Quality_Id { get; set; }
[Display(Name = "Design")]
public int Design_Id { get; set; }
[Display(Name = "Supplier")]
public int Supplier_Id { get; set; }
[Required]
[StringLength(20)]
[Display(Name = "Color")]
public string PColor { get; set; }
[Required]
[StringLength(20)]
[Display(Name = "Border Color")]
public string PBorder_Color { get; set; }
[Required]
[Display(Name = "Stock #")]
public string PSKU { get; set; }
[Display(Name = "Length")]
public decimal PLength { get; set; }
[Display(Name = "Width")]
public decimal PWidth { get; set; }
[Display(Name = "Cost")]
public decimal PCost { get; set; }
[Display(Name = "In Stock")]
public bool IsSold { get; set; }
public virtual Design Design { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Order_Details> Order_Details { get; set; }
public virtual Quality Quality { get; set; }
public virtual Supplier Supplier { get; set; }
}
}
You are not building your model nor invoking the overload of View() that accepts a model, so your model is null.
public ActionResult ViewCarpets()
{
IEnumerable<SelectListItem> Qualities = context.Qualities.Select(c => new SelectListItem
{
Value = c.Quality_Id.ToString(),
Text = c.QName
});
IEnumerable<SelectListItem> Suppliers = context.Suppliers.Select(c => new SelectListItem
{
Value = c.Supplier_Id.ToString(),
Text = c.SName
});
IEnumerable<SelectListItem> Designs = context.Design.Select(c => new SelectListItem
{
Value = c.Design_Id.ToString(),
Text = c.DName
});
ViewBag.Quality_Id = Qualities;
ViewBag.Supplier_Id = Suppliers;
ViewBag.Design_Id = Designs;
var products = GetProducts(); // whatever you need to do to get a list of products, database call etc.
return View("ViewCarpets", model: products);
}
You don't pass model to view:
return View("ViewCarpets");
Should be:
var model = new Your_model_class(); // Product for example
return View("ViewCarpets", model);
Thank you so much for the help guys, I got a hint from #Dan D so I changed my action method like below and the problem is solved
public ActionResult ViewCarpets()
{
//TODO: Implement View Carpets Logic
IEnumerable<SelectListItem> Qualities = context.Qualities.Select(c => new SelectListItem
{
Value = c.Quality_Id.ToString(),
Text = c.QName
});
IEnumerable<SelectListItem> Suppliers = context.Suppliers.Select(c => new SelectListItem
{
Value = c.Supplier_Id.ToString(),
Text = c.SName
});
IEnumerable<SelectListItem> Designs = context.Design.Select(c => new SelectListItem
{
Value = c.Design_Id.ToString(),
Text = c.DName
});
var model = new Product();
ViewBag.Quality_Id = Qualities;
ViewBag.Supplier_Id = Suppliers;
ViewBag.Design_Id = Designs;
List<Product> product = context.Products.ToList();
return View(product);
}

Passing a parameter to Html.ActionLink

I am trying to pass a parameter to the Create #Html.ActionLink in the Index view however I am having some difficulties.
I have an Address controller in which the user sees the addresses of a specific person when they access the Index view. I would like to pass this PersonID to the Create view so that they do not have to select or enter the person when they create a new address. My actionlink looks like this -
#Html.ActionLink("Create New", "Create", new { id = Model.[PersonID is not a choice]})
My problem is that after Model PersonID is not an option. I am not sure how to get PersonID to the Create function in the AddressController.
I tried following along with the post - Passing a parameter to Html.ActionLink when the model is IEnumerable<T> - where they are having the same issue. The first answers seems like a likely solution however I could not duplicate the model they created and when I put the pieces in my Address model I could not duplicate the code they had performed in the controller. Is there another solution?
My Address Model -
public partial class Address
{
public int AddressID { get; set; }
public int PersonID { get; set; }
[Display(Name="Address")]
public string Address1 { get; set; }
[Display(Name = "Address 2")]
public string Address2 { get; set; }
public string City { get; set; }
[Display(Name="State")]
public string StateAbbr { get; set; }
[Display(Name = "Zip Code")]
public string Zip { get; set; }
public virtual Person Person { get; set; }
public List<Address> Address { get; set; }
}
My AddressController Index
public ActionResult Index(int id)
{
var addresses = db.Addresses.Include(a => a.Person)
.Where(a => a.PersonID == id);
Person person = db.People.Find(id);
ViewBag.FullName = person.FirstName + " " + person.LastName;
person.PersonID = id;
return View(addresses.ToList());
}
Address Index view -
#model IEnumerable<OpenBurn.Models.Address>
#{
ViewBag.Title = "Address";
}
<h2>Address</h2>
<p>
#Html.ActionLink("Create New", "Create", new { id = .PerosnID })
</p>
<h3 style="color: #008cba;"> #ViewBag.FullName </h3>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Address1)
</th>
<th>
#Html.DisplayNameFor(model => model.Address2)
</th>
<th>
#Html.DisplayNameFor(model => model.City)
</th>
<th>
#Html.DisplayNameFor(model => model.StateAbbr)
</th>
<th>
#Html.DisplayNameFor(model => model.Zip)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Address1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address2)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.StateAbbr)
</td>
<td>
#Html.DisplayFor(modelItem => item.Zip)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.AddressID }) |
#Html.ActionLink("Details", "Details", new { id=item.AddressID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.AddressID })
</td>
</tr>
}
</table>
Since the #Html.ActionLink syntax isn't inside a foreach loop, you obviously can't use IEnumerable<OpenBurn.Models.Address> as the model. You need a new model class that contains a property that holds those Address records and a property that holds the PersonID value. You should also use the same model class to pass the FullName value instead of using ViewBag. I would suggest the below model class
public class AddressIndexModel
{
public AddressIndexModel()
{
this.Addresses = new List<Address>();
}
public int PersonID { get; set; }
public string FullName { get; set; }
public List<Address> Addresses { get; set; }
}
then change your controller to this
public ActionResult Index(int id)
{
var addresses = db.Addresses.Include(a => a.Person)
.Where(a => a.PersonID == id);
Person person = db.People.Find(id);
AddressIndexModel model = new AddressIndexModel();
model.PersonID = id;
model.FullName = person.FirstName + " " + person.LastName;
model.Addresses = addresses.ToList();
return View(model);
}
and change your view to below
#model AddressIndexModel
#{
ViewBag.Title = "Address";
}
<h2>Address</h2>
<p>
#Html.ActionLink("Create New", "Create", new { id = Model.PersonID })
</p>
<h3 style="color: #008cba;"> #Model.FullName </h3>
<table class="table">
<tr>
<th>
Address
</th>
<th>
Address 2
</th>
<th>
City
</th>
<th>
State
</th>
<th>
Zip Code
</th>
<th></th>
</tr>
#foreach (var item in Model.Addresses) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Address1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address2)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.StateAbbr)
</td>
<td>
#Html.DisplayFor(modelItem => item.Zip)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.AddressID }) |
#Html.ActionLink("Details", "Details", new { id=item.AddressID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.AddressID })
</td>
</tr>
}
</table>

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)

How to pass complex object collections to the controller in mvc

I'm new to MVC and sorry for this beginners question. I have following Model classes:
public class ReturnBookHedModel
{
public int RefferenceID { get; set; }
public int BorrowedRefNo { get; set; }
public int MemberId { get; set; }
public DateTime ReturnDate { get; set; }
public bool IsNeedToPayFine { get; set; }
public DateTime CurrentDate { get; set; }
public virtual List<ReturnBookDetModel> RetunBooks { get; set; }
public virtual MemberModel member { get; set; }
}
public class ReturnBookDetModel
{
public int BookID { get; set; }
public int RefferenceID { get; set; }
public bool IsReturned { get; set; }
public virtual ReturnBookHedModel ReturnBookHed { get; set; }
public virtual BookModel book { get; set; }
}
I have following controller methods:
public ActionResult SaveReturnBook(int refNo)
{
ReturnBookHedModel model = ReturnBookFacade.GetReturnBookBasedOnRefference(refNo);
return View(model);
}
//
// POST: /ReturnBook/Create
[HttpPost]
public ActionResult SaveReturnBook(ReturnBookHedModel model)
{
try
{
// TODO: Add insert logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
in my model i define as follows:
<div class="control-label">
#Html.LabelFor(model => model.BorrowedRefNo)
#Html.TextBoxFor(model => model.BorrowedRefNo, new { #class = "form-control" ,#readonly = "readonly" })
#Html.ValidationMessageFor(model => model.BorrowedRefNo)
</div>
// rest of the header details are here
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.RetunBooks.FirstOrDefault().IsReturned)
</th>
<th>
#Html.DisplayNameFor(model => model.RetunBooks.FirstOrDefault().BookID)
</th>
<th>
#Html.DisplayNameFor(model => model.RetunBooks.FirstOrDefault().book.BookName)
</th>
<th></th>
</tr>
#foreach (var item in Model.RetunBooks)
{
<tr >
<td>
#Html.CheckBoxFor(modelItem => item.IsReturned)
</td>
<td>
#Html.HiddenFor(modelItem => item.BookID);
#Html.DisplayFor(modelItem => item.BookID)
</td>
<td>
#Html.DisplayFor(modelItem => item.book.BookName)
</td>
</tr>
}
</table>
this is working fine.. but these table details (complex objects) are not in the controller's post method. when i searched i found that i can use this detail data as follows: but i cant use it as follows.
#for (var i = 0; i < Model.RetunBooks.Count; i++)
{
<tr>
<td>
#Html.CheckBoxFor(x => x.RetunBooks.)
</td>
</tr>
}
how can i send these information to controller
In order for the collection to be posted back you need to index them in the following way for the model binder to pick them up.
This should do the trick:
#for (var i = 0; i < Model.RetunBooks.Count; i++)
{
...
#Html.CheckBoxFor(model => Model.RetunBooks[i].IsReturned)
...
}
Complex objects require the indexing in the above manner.
For more info on it see here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

Categories