Use virtual properties to populate objects in lists - c#

I am struggling to find solid material regarding the use of virtual properties in C#/.NET.
One example where I am trying to simplify many calls to a DB is:
Creating an Order:
Order.cs includes:
[Key, Required]
public int Id { get; set; }
[Required, ForeignKey(nameof(Patient))]
public int PatientId { get; set; }
[Required, ForeignKey(nameof(Physician))]
public int PhysicianId { get; set; }
public virtual Patient Patient { get; set; }
public virtual Physician Physician { get; set; }
Patient and Physician contain many properties such as First Name, Last Name, Date-of-birth, etc.
When I create a new order, I am currently trying to hardcode the virtual property 'Patient':
var patient = _context.Patients.Where(x => x.Id == o.PatientId).FirstOrDefault();
o.Patient = patient;
and for 'Physician' I am using a SelectList ViewBag:
var physicians = _context.Physician
.Select(x => new
{
Id = x.Id,
FullName = $"{x.LastName}, {x.FirstName}",
LastName = x.LastName,
FirstName = x.FirstName
})
.ToList();
ViewData["PhysicianId"] = new SelectList(physicians.OrderBy(x => x.FullName).ToList(), "Id", "FullName", order.PhysicianId);
<div class="col-sm-6">
#Html.DisplayNameFor(m => m.Physician)
#Html.DropDownListFor(m => m.PhysicianId, ViewData["PhysicianId"] as SelectList, new { #id = "physicians", #class = "form-control w-100" })
#Html.ValidationMessageFor(m => m.PhysicianId)
</div>
The ViewBag method has worked for me before, but isn't now and I don't know why.
How do I use virtual properties (as objects) correctly to populate Order Details, both individually and in a list? Currently 'Patient' and 'Physician' return null.
View:
<td>
#Html.DisplayFor(modelItem => item.Patient.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Physician.LastName)
</td>
Controller:
var orders = await _context.Orders.ToListAsync();
return View("Index", orders.OrderByDescending(m => m.OrderDate).ToList());
How do I go the other way around... displaying a virtual list of Orders when pulling a Patient or Physician?

Try the below code, use .Include:
var orders = await _context.Orders.Include(e => e.Physician).Include(e => e.Patient).ToListAsync();

Related

Using a viewmodel and passing a query to the same view

I am new to mvc architecture. I want to create a view with a form to store data to db and a division to show the details using a query.This view is using a viewmodel- Add_session_ViewModel.
The issue is that if I am including the viewmodel to view there is an error in display section and if I am including the list there is a error in form.
The codes are as follows:
CONTROLLER:
public ActionResult Add_session()
{
//display data
var query =( from a in db.Session_details_feedback
join b in db.Employee_Details_Feedback on a.Trainer_id equals b.Emp_id
select new
{
a.Session_date,
a.Session_name,
b.Emp_name
} ).ToList();
foreach (var item in query)
{
List<Add_session_ViewModel> sessionList = new List<Add_session_ViewModel>
{
new Add_session_ViewModel { Session_name=item.Session_name,Session_date=item.Session_date,emp_name=item.Emp_name}
};
ViewData.Model = sessionList;
return View(ViewData.Model);
}
VIEWMODEL:
public class Add_session_ViewModel : DbContext
{
public string Session_name { get; set; }
public int Trainer_id { get; set; }
public System.DateTime Session_date { get; set; }
public string emp_name { get; set; }
public IList<Add_session_ViewModel> Session_List { get; set; }
}
VIEW:
#using (Html.BeginForm("Add_session", "Home", FormMethod.Post, new { #class = "form-horizontal" }))
{
<div class="form-group">
#Html.TextBoxFor(x => x.Session_name, new { #class = "form-control", placeholder = " Enter Session name" })
</div>
<div class="form-group">
#Html.TextBoxFor(x => x.Session_date, new { #class = "form-control", placeholder = " Enter Session date" })
</div>
<div class="form-group">
#Html.DropDownListFor(x => x.Trainer_id, ViewBag.TrainerList as IEnumerable<SelectListItem>, "Select Trainer")
</div>
<div class="form-group">
<input id="add" type="submit" value="ADD" />
</div>
}
</div>
</div>
</center>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Session</th>
<th>Trainer</th>
</tr>
</thead>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Session_date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Session_name)
</td>
<td>
#Html.DisplayFor(modelItem => item.emp_name)
</td>
</tr>
}
</table>
I have been looking for a solution for days, still didnt get any.
It would be appreciative if anyone can give me a solution.
Thank you.
my viewmodel is :
public class Add_session_ViewModel
{
public string Session_name { get; set; }
public int Trainer_id { get; set; }
public System.DateTime Session_date { get; set; }
public string emp_name { get; set; }
}
the view use all these properties through a form.
At the same time I need to get the data using the below query and get it displayed on the same view:
var query =( from a in db.Session_details_feedback
join b in db.Employee_Details_Feedback on a.Trainer_id equals b.Emp_id
select new
{
a.Session_date,
a.Session_name,
b.Emp_name
} ).ToList();
I have no ides how to bind the query and viewmodel to the view at the same time
First of all,
Remove the DbContext as base class to your view model,
public class Add_session_ViewModel
{
public string Session_name { get; set; }
public int Trainer_id { get; set; }
public System.DateTime Session_date { get; set; }
public string emp_name { get; set; }
public IList<Add_session_ViewModel> Session_List { get; set; }
}
Then try to map your LINQ query result to directly list of your view model.
public ActionResult Add_session()
{
Add_session_ViewModel model = new Add_session_ViewModel();
var result =(from a in db.Session_details_feedback
join b in db.Employee_Details_Feedback on a.Trainer_id equals b.Emp_id
select new Add_session_ViewModel //<= Note here
{
Session_date = a.Session_date,
Session_name = a.Session_name,
emp_name = b.Emp_name
}).ToList();
model.Session_List = result;
return View(model); //<= Return model to view instead of "ViewData"
}
And then your view must have a view model of
#model FeedBack_Form.Models.Add_session_ViewModel
And change your foreach loop to
#foreach (var item in Model.Session_List)

convert ipagedList anonymous type to ipagedList Model

[1] i want to pass the anonymous list to the view but I'm finding it difficult
please help me with the code:
i have the Model as :
namespace OpenOrderFramework.Models
{
[Bind(Exclude = "ID")]
public class Item
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
[Key]
[ScaffoldColumn(false)]
public int ID { get; set; }
[DisplayName("Catagorie:")]
public int CatagorieId { get; set; }
[Required(ErrorMessage = " Item name cannot be empty, this is required")]
[DisplayName("Item Name")]
public string ItemName { get; set; }
[DisplayName("GRC TAG")]
public string GRCTag { get; set; }
[DisplayName("Location:")]
public int LocationId { get; set; }
[DisplayName("Item Name:")]
public int itemnameId { get; set; }
[Required(ErrorMessage = "Quantity of item in a Location is required!")]
[DisplayName("Quantity in Store:")]
public int ItemQty { get; set; }
public DateTime DateCreated { get; set; }
controller is:
private ApplicationDbContext db = new ApplicationDbContext();
// GET: Items
public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "Name";
ViewBag.PriceSortParm = sortOrder == "Name" ? "Loc_desc" : "Location";
IEnumerable<Item> items = db.Items;
var ko= (from r in items.GroupBy(x => new { x.Catagorie, x.ItemName })
.Select(g => new
{
Catagorie = g.Key.Catagorie.Name,
ItemName = g.Key.ItemName,
ItemQty = g.Sum(s => s.ItemQty),
Location = g.First().Location.Name
})
select r).ToList();
if (!string.IsNullOrWhiteSpace(searchString))
{
items = items.Where(s => s.ItemName.Contains(searchString.ToUpper())
|| s.Catagorie.Name.ToUpper().Contains(searchString.ToUpper()) ||
s.Location.Name.ToUpper().Contains(searchString.ToUpper())).ToList().ToPagedList(page ?? 1, 20);
//}
}
else
{
items = items.ToList().ToPagedList(page ?? 1, 10);
}
return View(ko.ToList().ToPagedList(page ?? 1, 20));
}
and the View is :
#model PagedList.IPagedList<OpenOrderFramework.Models.Item>
#using PagedList.Mvc;
#using PagedList;
<table class="table">
<tr>
<th>
Catagory
</th>
<th>
Item Name.
</th>
<th>
Quantity.
</th>
#foreach (var item in Model)
{
<tr>
<td>
<font color="RED">
#Html.DisplayFor(modelItem => item.Catagorie.Name)
</font>
</td>
<td>
#Html.DisplayFor(modelItem => item.ItemName)
</td>
<td>
#Html.DisplayFor(modelItem => item.ItemQty)
</td>
[2] please help me with the code and return the filterd list to the view .
tried so many but not working.. got this error
The model item passed into the dictionary is of type 'PagedList.PagedList1[<>f__AnonymousType74[System.String,System.String,System.Int32,System.String]]', but this dictionary requires a model item of type 'PagedList.IPagedList`1[OpenOrderFramework.Models.Item]'
please help me with the code to return the anonymous list to my ipagedlist
I'm not sure about your OpenOrderFramework.Models.Item class but as can infer from code you need to add "new Item":
var ko= (from r in items.GroupBy(x => new { x.Catagorie, x.ItemName })
.Select(g => new new Item
{
Catagorie = g.Key.Catagorie.Name,
ItemName = g.Key.ItemName,
ItemQty = g.Sum(s => s.ItemQty),
Location = g.First().Location.Name
})
select r).ToList();
in thew view you are defining the expected model
#model PagedList.IPagedList<OpenOrderFramework.Models.Item>
So, you are able to pass a anonymous type to the view, BUT, you won't be able to have a strongly typed class in the view since it is anonymous. You cannot have the best of both worlds (thats the point of being anonymous)
Solution 1. You want strongly typed and intelli-sense
Declare a class and forget about anonymous, don't be shy ;)
public class Item
{
public string Catagorie{get; set;}
public string ItemName{get; set;}
public int ItemQty{get; set;}
public string Location{get; set;}
}
Query will be something similar to this:
var ko= (from r in items.GroupBy(x => new { x.Catagorie, x.ItemName })
.Select(g =>
new Item()
{
Catagorie = g.Key.Catagorie.Name,
ItemName = g.Key.ItemName,
ItemQty = g.Sum(s => s.ItemQty),
Location = g.First().Location.Name})
select r).ToList();
Last, change the model to be your recently declared class:
#model PagedList.IPagedList<YOURNS.Item>
Solution 2
Remove the #model declaration in the view and write the names of the variables without using strongly typed help. Just the name.
#foreach (var item in Model)
{
<tr>
<td>
<font color="RED">
#Html.Display("Catagorie")
</font>
</td>
<td>
#Html.Display("ItemName")
</td>
<td>
#Html.Display("ItemQty")
</td>

How to show a dropdown list in Razor

I'm having some troubles with Models and ViewModels.
I need list all bills and the users in the same view. (users in a dropdown list)
Also: When to use IEnumerable<T>? Because depending I change the view change the error message.
Model
public class Bill
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime Date { get; set; }
public string Category { get; set; }
public double Amount { get; set; }
public Card Card { get; set; }
public int CardId { get; set; }
}
ViewModel
public class UserBills
{
public IEnumerable<ApplicationUser> User { get; set; }
public Bill Bill { get; set; }
}
View
#*#model IEnumerable<Nucontrol.Models.Bill>*#
#model IEnumerable<Nucontrol.ViewModels.UserBills>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Bill.Card.Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bill.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bill.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bill.Category)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bill.Amount)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Bill.Id }) |
#Html.ActionLink("Details", "Details", new { id = item.Bill.Id }) |
#Html.ActionLink("Split", "Split", new { id = item.Bill.Id }, new { data_target = "#myModal", data_toggle = "modal" })
</td>
</tr>
}
<!-- List all users -->
#Html.DropDownListFor(m => User.Identity.Name, new SelectList(User.Identity.Name, "Id", "Name"), "", new { #class = "form-control" })
Controller
public ActionResult Index()
{
var users = _context.Users.ToList();
var bills = _context.Bills.ToList();
var viewModel = new UserBills
{
User = users
};
return View(viewModel);
}
You have some issues in sample code provided:
1) The DropDownListFor uses User.Identity.Name property as model binding, which actually derived from IIdentity.Name which is getter-only property. Declare another property with setter available which holds user ID in your viewmodel.
2) Passing UserBills viewmodel into view which bound to IEnumerable<UserBills> model may cause InvalidOperationException. You need to use either passing IEnumerable<UserBills> from controller or define #model UserBills.
3) I suggest you use IEnumerable<SelectListItem> to create DropDownListFor items from IEnumerable<ApplicationUser> generated by identity data context and pass it to view (see also IdentityUser properties).
Here is initial solution based from my thought:
Model
public class UserBills
{
public int UserId { get; set; }
public IEnumerable<SelectListItem> Users { get; set; }
public IEnumerable<Bill> Bills { get; set; }
}
Controller
public ActionResult Index()
{
var users = _context.Users.ToList();
var bills = _context.Bills.ToList();
var viewModel = new UserBills
{
Users = users.Select(x => new SelectListItem() { Value = x.Id.ToString(), Text = x.UserName.ToString() }),
Bills = bills
}
return View(viewModel);
}
View
#model Nucontrol.ViewModels.UserBills
#foreach (var item in Model.Bills)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Card.Number)
</td>
<!-- other properties -->
</tr>
}
#Html.DropDownListFor(m => m.UserId, Model.Users, "", new { #class = "form-control" })
NB: Since you're getting selected user ID from viewmodel binding, it is possible to create HttpContext.User instance and setting User.Identity.Name property from that ID.

Convention for adding items to a collection property from a select list in the create portion of CRUD?

My main entity is the Recipe which contains a collection of Ingredient items as follows:
public class Recipe {
[Key]
public virtual int RecipeId { get; set; }
public string RecipeName { get; set; }
...
public virtual ApplicationUser LastModifiedBy { get; set; }
public virtual IList<Ingredient> Ingredients { get; set; }
}
public class Ingredient {
public virtual int IngredientId { get; set; }
[Display(Name = "Name")]
public string IngredientName { get; set; }
....
public virtual IList<Recipe> Recipes { get; set; }
}
Which is fine. Then my controller and view for creating a new Recipe are as follows:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "stuff to include")] Recipe recipe)
{
IList<int> ingredientIds = (ModelState.Values.ElementAt(1).Value.AttemptedValue).Split(',').Select(int.Parse).ToList(); //[1,2,3,4,5]
foreach (int id in ingredientIds) {
Ingredient ing = db.Ingredients.Where(i => i.IngredientId == id).FirstOrDefault() as Ingredient;
recipe.Ingredients.Add(ing);
}
db.Recipes.Add(recipe);
db.SaveChanges();
return RedirectToAction("Index");
ViewBag.Ingredients = new MultiSelectList(db.Ingredients,
"IngredientId", "IngredientName", string.Empty);
ViewBag.CreatedById = new SelectList(db.Users, "Id", "Email", recipe.CreatedById);
return View(recipe);
}
And the view:
#for (Int16 i = 0; i < 5; i++) {
<div class="form-group">
#Html.LabelFor(model => model.Ingredients, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("Ingredients", null, htmlAttributes: new { #class = "form-control" })
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" value="Add Ingredients" class="btn btn-default" />
</div>
</div>
So this sets ModelState.Values.ElementAt(1).Value.AttemptedValue = "1,3,5,4,5" where this is a list of id numbers. I know I can come in before the if (ModelState.IsValid) and iterate through the above and place it into recipe.Ingredients which is fine except...
It feels just so un ASP.NET MVC like, as if there's no way they could have thought of so much and not thought of this scenario? Am I missing something here? The ingredients list will be too long to make a multi select list any use.
You are creating arbitrary dropdownlists that all have the same id (invalid html) and name attribute that has no relationship to your model and wont bind on post back. You first need to create view models that represent what you want to display.
public class RecipeVM
{
[Required]
public string Name { get; set; }
[Display(Name = Ingredient)]
[Required]
public List<int?> SelectedIngredients { get; set; }
public SelectList IngredientList { get; set; }
}
Then in the controller
public ActionResult Create()
{
RecipeVM model = new RecipeVM();
// add 5 'null' ingredients for binding
model.SelectedIngredients = new List<int?>() { null, null, null, null, null };
ConfigureViewModel(model);
return View(model);
}
[HttpPost]
public ActionResult Create(RecipeVM model)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model);
}
// Initialize new instance of your data model
// Map properties from view model to data model
// Add values for user, create date etc
// Save and redirect
}
private void ConfigureViewModel(RecipeVM model)
{
model.IngredientList = new SelectList(db.Ingredients, "IngredientId", "IngredientName");
}
View
#model RecipeVM
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
#Html.ValidationMessageFor(m => m.Name)
for (int i = 0; i < Model.SelectedIngredients.Count; i++)
{
#Html.LabelFor(m => m.SelectedIngredients[i])
#Html.DropDownListFor(m => m.SelectedIngredients[i], Model.IngredientList, "-Please select-")
}
}
Note this is based on your current implementation of creating 5 dropdowns to select 5 ingredients. In reality you will want to dynamically add ingredients (start with none). The answers here and here give you a few options to consider.

MVC 4 - Many-to-Many relation and checkboxes

I'm working with ASP.NET MVC 4 and Entity Framework. In my database, I have a table Subscription which represents a subscription to public transports. This subscription can provide access to several public transport companies (so a subscription could have 1, 2, 3, ... companies) then it is a Many-to-Many relation between these tables (I have an intermediate table between them).
I want to allow the creation of a subscription throught a page which will contain a field Amount of the subscription and the available companies by checkboxes. Every checkbox represents an existing company (a company stored in my database).
Any idea about how to do that? I've read this ASP.NET MVC Multiple Checkboxes but it was not really helpful.
EDIT : Here is my tables diagram.
You start with two view models. The first one which represents a selected company...
public class CompanySelectViewModel
{
public int CompanyId { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
...and the second one for the subscription to create:
public class SubscriptionCreateViewModel
{
public int Amount { get; set; }
public IEnumerable<CompanySelectViewModel> Companies { get; set; }
}
Then in the SubscriptionControllers GET action you load the companies from the database to initialize the view model:
public ActionResult Create()
{
var viewModel = new SubscriptionCreateViewModel
{
Companies = _context.Companies
.Select(c => new CompanySelectViewModel
{
CompanyId = c.CompanyId,
Name = c.Name,
IsSelected = false
})
.ToList()
};
return View(viewModel);
}
Now, you have a strongly typed view for this action:
#model SubscriptionCreateViewModel
#using (Html.BeginForm()) {
#Html.EditorFor(model => model.Amount)
#Html.EditorFor(model => model.Companies)
<input type="submit" value="Create" />
#Html.ActionLink("Cancel", "Index")
}
To get the company checkboxes rendered correctly you introduce an editor template. It must have the name CompanySelectViewModel.cshtml and goes into the folder Views/Subscription/EditorTemplates (create such a folder manually if it doesn't exist). It's a strongly typed partial view:
#model CompanySelectViewModel
#Html.HiddenFor(model => model.CompanyId)
#Html.HiddenFor(model => model.Name)
#Html.LabelFor(model => model.IsSelected, Model.Name)
#Html.EditorFor(model => model.IsSelected)
Name is added as hidden field to preserve the name during a POST.
Obviously you have to style the views a bit more.
Now, your POST action would look like this:
[HttpPost]
public ActionResult Create(SubscriptionCreateViewModel viewModel)
{
if (ModelState.IsValid)
{
var subscription = new Subscription
{
Amount = viewModel.Amount,
Companies = new List<Company>()
};
foreach (var selectedCompany
in viewModel.Companies.Where(c => c.IsSelected))
{
var company = new Company { CompanyId = selectedCompany.CompanyId };
_context.Companies.Attach(company);
subscription.Companies.Add(company);
}
_context.Subscriptions.Add(subscription);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}
Instead of using Attach you can also load the company first with var company = _context.Companies.Find(selectedCompany.CompanyId);. But with Attach you don't need a roundtrip to the database to load the companies to be added to the collection.
(Edit 2: In this answer is a continuation for the Edit actions and views with the same example model.)
Edit
Your model is not really a many-to-many relationship. You have two one-to-many relationships instead. The PublicTransportSubscriptionByCompany entity is not needed - normally. If you have a composite primary key in that table made of Id_PublicTransportSubscription, Id_PublicTransportCompany and remove the id column Id_PublicTransportSubscriptionByCompanyId EF would detect this table schema as a many-to-many relationship and create one collection in each of the entities for subscription and company and it would create no entity for the link table. My code above would apply then.
If you don't want to change the schema for some reason you must change the POST action like so:
[HttpPost]
public ActionResult Create(SubscriptionCreateViewModel viewModel)
{
if (ModelState.IsValid)
{
var subscription = new Subscription
{
Amount = viewModel.Amount,
SubscriptionByCompanies = new List<SubscriptionByCompany>()
};
foreach (var selectedCompany
in viewModel.Companies.Where(c => c.IsSelected))
{
var company = new Company { CompanyId = selectedCompany.CompanyId };
_context.Companies.Attach(company);
var subscriptionByCompany = new SubscriptionByCompany
{
Company = company
};
subscription.SubscriptionByCompanies.Add(subscriptionByCompany);
}
_context.Subscriptions.Add(subscription);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}
I prefer this answer: Saving Many to Many relationship data on MVC Create view
If you are doing database first, then just skip to the viewmodel part of section 1.
Just an extension to Slauma's answer. In my case i had to represent many-to-many like a table between Products and Roles, first column representing Products, the header representing Roles and the table to be filled with checkboxes to select roles for product.
To achieve this i have used ViewModel like Slauma described, but added another model containing the last two, like so:
public class UserViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<ProductViewModel> Products { get; set; }
}
public class ProductViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<RoleViewModel> Roles { get; set; }
}
public class RoleViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
Next, in Controller we need to fill data:
UserViewModel user = new UserViewModel();
user.Name = "Me";
user.Products = new List<ProductViewModel>
{
new ProductViewModel
{
Id = 1,
Name = "Prod1",
Roles = new List<RoleViewModel>
{
new RoleViewModel
{
Id = 1,
Name = "Role1",
IsSelected = false
}
// add more roles
}
}
// add more products with the same roles as Prod1 has
};
Next, in View:
#model UserViewModel#using (Ajax.BeginForm("Create", "User",
new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "divContainer"
}))
{
<table>
<thead>
<tr>
<th>
</th>
#foreach (RoleViewModel role in Model.Products.First().Roles.ToList())
{
<th>
#role.Name
</th>
}
</tr>
</thead>
<tbody>
#Html.EditorFor(model => model.Products)
</tbody>
</table>
<input type="submit" name="Create" value="Create"/>
}
As you see, EditorFor is using template for Products:
#model Insurance.Admin.Models.ProductViewModel
#Html.HiddenFor(model => model.Id)
<tr>
<th class="col-md-2 row-header">
#Model.Name
</th>
#Html.EditorFor(model => model.Roles)
</tr>
This template uses another template for Roles:
#model Insurance.Admin.Models.RoleViewModel
#Html.HiddenFor(model => model.Id)
<td>
#Html.EditorFor(model => model.IsSelected)
</td>
And voila, we have a table containing first column Products, the header contains Roles and the table is filled with checkboxes. We are posting UserViewModel and you will see that all the data are posted.

Categories