Why the result from linq to viewmodel been duplicate in MVC - c#

Good day all,
I'm new in MVC.
The Issue : The data repeated (duplicate).
Suppose diffrent data populate but it appear same record.
it took last record and shows all records same (duplicate).
i dont know where is my mistake.
i checked 'Qdata' populate correct data. but when go to view model been duplicate.
Controller
List<ApprovalVM> SmPSetVM = new List<ApprovalVM>();
ApprovalVM setVM = new ApprovalVM();
var Qdata = (from u in db.SSM_RegisSet
join c in db.SSM_LinkRegisUpload on u.PKRegisId equals c.FKRegisId
join v in db.SSM_UploadData on c.FKUpDid equals v.UplId
join b in db.SSM_User on u.FKUserId equals b.PK_Uid
join g in db.SSM_Department on b.FK_DepartId equals g.PK_DeptId
join t in db.SSM_Team on b.FK_TeamId equals t.PK_TeamId
join k in db.SSM_GM on b.FK_GMId equals k.PK_GM_id
//where v.SN_NO == da
//orderby u.AutoEC_id
select new
{
v.PO_NO,
v.SN_NO,
v.Exp_NO,
v.Model,
v.PlanDate,
v.Holder_Id,
ids = "I000" + u.PKRegisId,
c.PKLinkId,
g.HODName,
b.PK_Uid,
b.UserName,
t.PK_TeamId,
t.TeamLeaderName,
k.GMName
}).ToList().OrderByDescending(v=>v.PKLinkId);
foreach (var item in Qdata)//.Where(x => x.SN_NO == da))
{
setVM.PO_NO = item.PO_NO;
setVM.SN_NO = item.SN_NO;
setVM.Exp_NO = item.Exp_NO;
setVM.Model = item.Model;
setVM.PlanDate = item.PlanDate;
setVM.Holder_Id = item.Holder_Id;
setVM.POSNId = item.ids;
setVM.PKLinkId = item.PKLinkId;
setVM.PK_TeamId = item.PK_TeamId;
setVM.HODName = item.HODName;
setVM.PK_Uid = item.PK_Uid;
setVM.UserName = item.UserName;
setVM.TeamLeaderName = item.TeamLeaderName;
setVM.GMName = item.GMName;
SmPSetVM.Add(setVM);
}
return View(SmPSetVM);
View Model
public class ApprovalVM
{
// User
public int PK_Uid { get; set; }
public string UserName { get; set; }
public string FullName { get; set; }
// Team Leader
public int PK_TeamId { get; set; }
public string TeamName { get; set; }
public string TeamLeaderName { get; set; }
// GM Name
public int PK_GM_id { get; set; }
public string GMName { get; set; }
public Nullable<bool> GMIsVisible { get; set; }
//Department
public int PK_DeptId { get; set; }
public string DepartmentName { get; set; }
public string HODName { get; set; }
//Upload Data
public int UplId { get; set; }
[Display(Name = "PO No")]
public string PO_NO { get; set; }
[Display(Name = "S/N")]
public string SN_NO { get; set; }
[Display(Name = "Exp No")]
public string Exp_NO { get; set; }
public string Model { get; set; }
public string PlanDate { get; set; }
public string Holder_Id { get; set; }
// Regis Id
public string POSNId { get; set; }
//Link
public int PKLinkId { get; set; }
// List of Approval
//public List<ApprovalVM> ListApproval { get; set; }
}
View
<div class="col-lg-11">
<div class="panel-body table-responsive">
<table class="table table-striped" id="IntTrntbl">
<tr>
<th>
No
</th>
<th>
#Html.DisplayNameFor(model => model.POSNId)
</th>
<th>
#Html.DisplayNameFor(model => model.PO_NO)
</th>
<th>
#Html.DisplayNameFor(model => model.SN_NO)
</th>
<th>
#Html.DisplayNameFor(model => model.Exp_NO)
</th>
<th>
#Html.DisplayNameFor(model => model.Model)
</th>
<th>
#Html.DisplayNameFor(model => model.PlanDate)
</th>
<th>
#Html.DisplayNameFor(model => model.Holder_Id)
</th>
<th>
#Html.DisplayNameFor(model => model.PKLinkId)
</th>
</tr>
#{int a = 1;}
#foreach (var item in Model)
{
<tr>
<td>
#(a++)
</td>
<td style="width:10%">
#Html.DisplayFor(modelItem => item.POSNId)
</td>
<td>
#Html.DisplayFor(modelItem => item.PO_NO)
</td>
<td>
#Html.DisplayFor(modelItem => item.SN_NO)
</td>
<td>
#Html.DisplayFor(modelItem => item.Exp_NO)
</td>
<td>
#Html.DisplayFor(modelItem => item.Model)
</td>
<td>
#Html.DisplayFor(modelItem => item.PlanDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Holder_Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.PKLinkId)
</td>
</tr>
}
</table>
</div>
</div>
Thanks In Advance!

It is because you don't instantiate a new setVM in foreach loop. You should move the initialization of setVM object(ApprovalVM setVM = new ApprovalVM();) in foreach loop.
In each iteration you modify the same object and add it to your list.

You are updating the same object in every iteration of the loop. You initialize the setVM once and then add it to the list many times. Therefore the list contains multiple entries of the same item. As you update the object in the foreach then all references that point to that item reference the new value.
Instantiate a new item in each iteration:
foreach (var item in Qdata)//.Where(x => x.SN_NO == da))
{
setVM = new ApprovalVM();
setVM.PO_NO = item.PO_NO;
setVM.SN_NO = item.SN_NO;
setVM.Exp_NO = item.Exp_NO;
setVM.Model = item.Model;
setVM.PlanDate = item.PlanDate;
setVM.Holder_Id = item.Holder_Id;
setVM.POSNId = item.ids;
setVM.PKLinkId = item.PKLinkId;
setVM.PK_TeamId = item.PK_TeamId;
setVM.HODName = item.HODName;
setVM.PK_Uid = item.PK_Uid;
setVM.UserName = item.UserName;
setVM.TeamLeaderName = item.TeamLeaderName;
setVM.GMName = item.GMName;
SmPSetVM.Add(setVM);
}
But if already using linq then you can improve and project this class in the query (and use the object initializer syntax):
return View((from u in db.SSM_RegisSet
join c in db.SSM_LinkRegisUpload on u.PKRegisId equals c.FKRegisId
join v in db.SSM_UploadData on c.FKUpDid equals v.UplId
join b in db.SSM_User on u.FKUserId equals b.PK_Uid
join g in db.SSM_Department on b.FK_DepartId equals g.PK_DeptId
join t in db.SSM_Team on b.FK_TeamId equals t.PK_TeamId
join k in db.SSM_GM on b.FK_GMId equals k.PK_GM_id
//where v.SN_NO == da
//orderby u.AutoEC_id
select new ApprovalVM {
PO_NO = v.PO_NO,
//And so on
}).OrderByDescending(v=>v.PKLinkId).ToList());
And last, if using EF then read into Navigation Properties. Will make joins much simpler.

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);
}

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

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());
}

Return a list in MVC causes an error

I am trying to return a list of schedule in education system. I have a schedule model in my Project with this property:
public partial class Schedule
{
public Schedule()
{
this.ClassTimes = new HashSet<ClassTime>();
this.Scores = new HashSet<Score>();
}
public int Id { get; set; }
public int TeacherId { get; set; }
public int LessonId { get; set; }
public int ClassId { get; set; }
public int DegreeId { get; set; }
public int FacultyId { get; set; }
public int SemesterId { get; set; }
public int MajorId { get; set; }
public System.DateTime DateOfExame { get; set; }
public string Capacity { get; set; }
public string locationOfExame { get; set; }
public virtual Class Class { get; set; }
public virtual ICollection<ClassTime> ClassTimes { get; set; }
public virtual Degree Degree { get; set; }
public virtual Faculty Faculty { get; set; }
public virtual Lesson Lesson { get; set; }
public virtual Major Major { get; set; }
public virtual ICollection<Score> Scores { get; set; }
public virtual Semester Semester { get; set; }
public virtual Teacher Teacher { get; set; }
}
So in this model I save the id of my entity for example major, teacher, lesson, etc. So I need to return a list of my schedules. So I have to convert the id of my entity to name of that entity. So I design a schedule controller in my MVC project like this:
private readonly ScheduleRepositor obj = new ScheduleRepositor();
public ActionResult Index()
{
var list=new List<SchedulePresentation>();
ClassRepository objclassrep=new ClassRepository();
DegreeRepositor objdegreerep=new DegreeRepositor();
FacultyRepositor objfactulyrep=new FacultyRepositor();
LessonRepository objLessonRep=new LessonRepository();
MajorRepository objmajorrep=new MajorRepository();
SemesterRepositor objsemesterrep=new SemesterRepositor();
TeacherRepositor objteacherrep=new TeacherRepositor();
DateConverter objdateconverte = new DateConverter();
List<Schedule> model = obj.GetLessonlist();
foreach (var t in model)
{
SchedulePresentation objpres=new SchedulePresentation();
objpres.Capacity = t.Capacity;
objpres.DateOfExam = objdateconverte.ConvertToPersianToShow(t.DateOfExame);
objpres.className = objclassrep.FindClassById(t.ClassId).ClassName;
objpres.degreeName = objdegreerep.FindDegreeById(t.DegreeId).DegreeName;
objpres.examLocation = t.locationOfExame;
objpres.facultyName = objfactulyrep.FindFacultyById(t.FacultyId).FacultyName;
objpres.lessonName = objLessonRep.FindLessonById(t.LessonId).LessonName;
objpres.majorName = objmajorrep.FindMajorById(t.MajorId).MajorName;
objpres.semesterName = objsemesterrep.FindSemesterById(t.SemesterId).SemesterName;
objpres.teacherName = objteacherrep.FindTeacherById(t.TeacherId).Name + " " +
objteacherrep.FindTeacherById(t.TeacherId).LastName;
list.Add(objpres);
}
return View(list);
}
So I just create a repository for each entity to return the name of my entity by id.
And I create a representation class for my schedule to convert the id to name of my entities like this:
public class SchedulePresentation
{
public string teacherName { set; get; }
public string lessonName { set; get; }
public string className { set; get; }
public string degreeName { set; get; }
public string facultyName { set; get; }
public string semesterName { set; get; }
public string majorName { set; get; }
public string DateOfExam { set; get; }
public string Capacity { set; get; }
public string examLocation { set; get; }
}
So I have two problems. I have 4 projects in my solution:
DomainClass
Model
Repository
MVC project
So
Is it a good method that I convert these Id to their name in the MVC layer, or it is better to make a Repository or create a model for this list of schedules?
In the last line when I want to return my list I got this error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[EducationMVC.PresentationClass.SchedulePresentation]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[DomainClasses.Schedule]'.
The view code of MVC :
#model IEnumerable<DomainClasses.Schedule>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.TeacherId)
</th>
<th>
#Html.DisplayNameFor(model => model.LessonId)
</th>
<th>
#Html.DisplayNameFor(model => model.ClassId)
</th>
<th>
#Html.DisplayNameFor(model => model.DegreeId)
</th>
<th>
#Html.DisplayNameFor(model => model.FacultyId)
</th>
<th>
#Html.DisplayNameFor(model => model.SemesterId)
</th>
<th>
#Html.DisplayNameFor(model => model.MajorId)
</th>
<th>
#Html.DisplayNameFor(model => model.DateOfExame)
</th>
<th>
#Html.DisplayNameFor(model => model.Capacity)
</th>
<th>
#Html.DisplayNameFor(model => model.locationOfExame)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.TeacherId)
</td>
<td>
#Html.DisplayFor(modelItem => item.LessonId)
</td>
<td>
#Html.DisplayFor(modelItem => item.ClassId)
</td>
<td>
#Html.DisplayFor(modelItem => item.DegreeId)
</td>
<td>
#Html.DisplayFor(modelItem => item.FacultyId)
</td>
<td>
#Html.DisplayFor(modelItem => item.SemesterId)
</td>
<td>
#Html.DisplayFor(modelItem => item.MajorId)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateOfExame)
</td>
<td>
#Html.DisplayFor(modelItem => item.Capacity)
</td>
<td>
#Html.DisplayFor(modelItem => item.locationOfExame)
</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>
Your view probably has a strongly typed model like this
#model IEnumerable<DomainClasses.Schedule>
but you are returning a List<SchedulePresentation>.
One solution would be to change the model line to: #model IEnumerable<SchedulePresentation>.
The answer to your question lies in the error message:
The model item passed into the dictionary is of type
'System.Collections.Generic.List1[EducationMVC.PresentationClass.SchedulePresentation]',
but this dictionary requires a model item of type
'System.Collections.Generic.IEnumerable1[DomainClasses.Schedule]'.
It seems like the view corresponding to this method (by default the Index view of your controller) is expecting a model of type IEnumerable<Schedule>.
If you wish to send a List<SchedulePresentation>, change the model type in the view to IEnumerable<SchedulePresentation>.
Hint: In your view, one of the first lines should be of the form:
#model IEnumerable<DomainClasses.Schedule>
which you could change like this:
#model IEnumerable<EducationMVC.PresentationClass.SchedulePresentation>
The answer lies in the error reported by the compiler. You're passing to a view a model object of a certain type (SchedulePresentation), when the view expects a model object of type Schedule.
In particular, in the lines:
List<Schedule> model = obj.GetLessonlist();
foreach (var t in model)
{
SchedulePresentation objpres=new SchedulePresentation();
objpres.Capacity = t.Capacity;
objpres.DateOfExam = objdateconverte.ConvertToPersianToShow(t.DateOfExame);
objpres.className = objclassrep.FindClassById(t.ClassId).ClassName;
objpres.degreeName = objdegreerep.FindDegreeById(t.DegreeId).DegreeName;
objpres.examLocation = t.locationOfExame;
objpres.facultyName = objfactulyrep.FindFacultyById(t.FacultyId).FacultyName;
objpres.lessonName = objLessonRep.FindLessonById(t.LessonId).LessonName;
objpres.majorName = objmajorrep.FindMajorById(t.MajorId).MajorName;
objpres.semesterName = objsemesterrep.FindSemesterById(t.SemesterId).SemesterName;
objpres.teacherName = objteacherrep.FindTeacherById(t.TeacherId).Name + " " +
objteacherrep.FindTeacherById(t.TeacherId).LastName;
list.Add(objpres);
}
you're creating a List<Schedule> but you add to it objects of type SchedulePresentation, when the model specified in your view expects the type IEnumerable<DomainClasses.Schedule>. For this reason, you have the error:
The model item passed into the dictionary is of type
'System.Collections.Generic.List1[EducationMVC.PresentationClass.SchedulePresentation]',
but this dictionary requires a model item of type
'System.Collections.Generic.IEnumerable1[DomainClasses.Schedule]'.
To solve the problem, change your model line to #model IEnumerable<SchedulePresentation>.
Regarding your first question, I'd say the MVC controller is the right place to extract the information from what the repository returns, and put it in a view model (your SchedulePresentation class). However, the code you posted will result in an aweful lot of database queries - for each item in your schedule, you'll end up with eight extra queries to get the related items. In a schedule with 20 items, that's an extra 160 database queries to get stuff you could probably have included.
You've tagged this [entity-framework], so I'm going to assume that you're using it to get the Schedule items from your database. Instead of using the id's of the items, use the actual properties:
for (var t in model) {
SchedulePresentation objpres=new SchedulePresentation();
objpres.Capacity = t.Capacity;
objpres.DateOfExam = objdateconverte.ConvertToPersianToShow(t.DateOfExame);
objpres.className = t.Class.ClassName; // <- this works!
}
Now, doing just that will not save you any db queries - it will just clean up your code a little. Due to lazy loading, EF will still retrieve the relevant Class object from the db when you ask to look at it, rather than at the top. However, if you in your repository add an Include statement to your EF query, you'll start saving - then EF will include the related items in the original query, and they will already be fetched from the db. This will look something like the following:
var ctx = getYourEFContextSomehow(); // pseudocode, obviously...
var scheduleItems = ctx.Schedules.Include(s => s.Class);
// Add more Include for other objects
There are other ways to turn off lazy loading for specific properties or entire objects as well - check out http://msdn.microsoft.com/en-us/data/jj574232

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