ASP.net MVC 5 Add data to multiple tables - asp.net-mvc

Hi thank you all for assisting me. I am very new to ASP.net MVC and EF and am playing around to do some real project. I would really appreciate if someone could please guide me of how I can insert data into two tables in SQL with one to many relationships.
I have a requirement where I need to add multiple families to one behavior case.
tblCase [case_id] [case_no]
tblFamily [family_id] [first_name] [last_name] [case_id]
After following an online tutorial I am able to add multiple families but I can not get my head around how to:
Add a new case -> retrieve the last inserted case_id
Add all the families with the last inserted case_id in one submit button click.
My view looks like the following:
#model List<TestMVC.Family>
#{
ViewBag.Title = "BulkData";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<style>
td {
padding: 5px;
}
</style>
<div style="width:700px; padding:5px; background-color:white;">
#using (Html.BeginForm("BulkData", "Save", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
if (ViewBag.Message != null)
{
<div style="border:solid 1px green">
#ViewBag.Message
</div>
}
<div id="dvCase">
<table>
<tr>
<td>Case Name</td>
<td><input type="text" value="" /></td>
</tr>
<tr>
<td>Case No</td>
<td><input type="text" value="" /></td>
</tr>
</table>
</div>
<div>Add New</div>
<table id="dataTable" border="0" cellpadding="0" cellspacing="0">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Case Id</th>
<th></th>
</tr>
#if (Model != null && Model.Count > 0)
{
int j = 0;
foreach (var i in Model)
{
<tr style="border:1px solid black">
<td>#Html.TextBoxFor(a => a[j].firstName)</td>
<td>#Html.TextBoxFor(a => a[j].lastName)</td>
<td>#Html.TextBoxFor(a => a[j].case_id)</td>
<td>
#if (j > 0)
{
Remove
}
</td>
</tr>
j++;
}
}
</table>
<input type="submit" value="Save" />
}
</div>
and my controller looks like :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace TestMVC.Controllers
{
public class SaveController : Controller
{
//
// GET: /Save/
public ActionResult BulkData()
{
Case bc = new Case {case_id=0,case_no=""};
// This is only for show by default one row for insert data to the database
List<Family> ci = new List<Family> { new Family { family_id = 0, firstName = "", lastName = "", case_id= 0 } };
return View(ci);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult BulkData(List<Family> ci)
{
if (ModelState.IsValid)
{
using (FamilyContext dc = new FamilyContext())
{
var behaveCase = new Case();
behaveCase.case_no = "1234";
dc.Cases.add(behaveCase);
foreach (var i in ci)
{
i.Case = behaveCase;
dc.Families.Add(i);
}
dc.SaveChanges();
ViewBag.Message = "Data successfully saved!";
ModelState.Clear();
ci = new List<Family> { new Family { family_id = 0, firstName = "", lastName = "", case_id = 0 } };
}
}
return View(ci);
}
}
}
and my model definitions
namespace TestMVC
{
using System;
using System.Collections.Generic;
public partial class Case
{
public Case()
{
this.Families = new HashSet<Family>();
}
public int case_id { get; set; }
public string case_no { get; set; }
public virtual ICollection<Family> Families { get; set; }
}
}
namespace TestMVC
{
using System;
using System.Collections.Generic;
public partial class Family
{
public int family_id { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public int case_id { get; set; }
public virtual Case Case { get; set; }
}
}

Model which is added that is 'i' over here : dc.Families.Add(i); when dc.SaveChanges() called it will modify 'i' with its primary key as :
if (ModelState.IsValid)
{
using (FamilyContext dc = new FamilyContext())
{
var behaveCase = new Case();
behaveCase.case_no = "1234";
dc.Cases.add(behaveCase);
dc.SaveChanges(); // Save Changes Occurred. primary key in inserted in behaveCase
int pk = behaveCase.case_id; // You can get primary key of your inserted row
foreach (var i in ci)
{
i.Case = behaveCase;
dc.Families.Add(i);
dc.SaveChanges(); // Save Changes Occured. Primary key of i is inserted
int pkFam = i.family_id; // You can get primary key of your inserted row
}
ViewBag.Message = "Data successfully saved!";
ModelState.Clear();
ci = new List<Family> { new Family { family_id = 0, firstName = "", lastName = "", case_id = 0 } };
}
}

Related

Get Null when Binding List of Object to Controller MVC Model

I am having trouble binding a model that contains list of objects for Editing method. This is the list of Factory which includes list of another object (FactoryHotline).
There is no problem when I get pass data from Controller to View. But when I try to send data from View back to Controller, some model's properties always null.
The Model is:
public class Factory
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<FactoryHotline> FactoryHotlineList { get; set; }
}
public class FactoryHotline
{
public Guid Id { get; set; }
public Guid FactoryId { get; set; }
public string Caption { get; set; }
public string Hotline { get; set; }
}
This is View:
#model List<WebDataLayer.Models.Factory>
<form action="/Factories/Edit" method="POST" enctype="multipart/form-data">
#Html.AntiForgeryToken()
<div class="form-horizontal">
<table id="factoriesTable">
<thead>
<tr>
<th>Name</th>
<th class="Hotline1" >Hotline 1</th>
<th class="Hotline2" >Hotline 2</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(model => model[i].Id)
<tr>
<td>#Model[i].Name</td>
#for (int h = 0; h < Model[i].FactoryHotlineList.Count; h++)
{
<td>
<div>
<b>Caption: </b>
#Html.EditorFor(model => model[i].FactoryHotlineList[h].Caption, new { htmlAttributes = new { #class = "form-control ShortInput", id = "captionInput", maxlength = "39" } })
</div>
<div>
<b>Hotline:</b>
#Html.EditorFor(model => model[i].FactoryHotlineList[h].Hotline, new { htmlAttributes = new { #class = "form-control ShortInput", id = "hotlineInput", maxlength = "15" } })
#Html.ValidationMessageFor(model => model[i].FactoryHotlineList[h].Hotline)
</div>
</td>
}
</tr>
}
</tbody>
</table>
</form>
In my controller the method for Edit is:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit (List<Factory> factories)
{
}
Only Id has value, the other(Caption, Hotline) are always null in List<Factory> factories
This is how I am passing Data from Controller to View
// GET: Edit
public ActionResult Edit()
{
var factories = _factoryService.All().OrderBy(p => p.Name);
var list = factories.ToList();
return View("Edit", list);
}
I works fine using Entity Framework.
That is because you have used HiddenFor to keep id as hidden field. To have the value in postback, it should be a part of input element(input,select,checkbox,textarea,etc) or as hidden field.
#Html.HiddenFor(model => model[i].Name)
I would suggest using a viewmodel along with automapper in this case.

Using multiple paginated lists on one HTML page

I'm MVC / Razor pages newbie so bear with me. I would like to display several lists of items on one page. These lists have 100+ items each so they need to be paginated. In Microsofts Entity Framework .net core tutorial I found only 1 pagination per page, so that cannot be used.
I feel like I should be using View Component to achieve this, but I'm quite not sure how to do it. Can anyone help me please?
I'm using Razor pages .net Core, but I'm not against using controller to achieve this
Thanks in advance
My view is:
#page
#model DOOR.Core.Web.Pages.Models.IndexModel
<h2 style="margin-top:20px "><span class="glyphicon glyphicon-compressed"></span> Model #Html.DisplayFor(model => Model.
<h4 class="h4-bold">Tables</h4>
#if (Model.PdModel.FirstOrDefault().PdTables.Count == 0)
{
#:Model doesn't contain any tables
}
else
{
<table class="table table-striped">
<thead>
<th>
Name
</th>
<th>
Description
</th>
<th>
Type
</th>
</thead>
#foreach (var tableItem in Model.PdModel.FirstOrDefault().PdTables.OrderBy(x => x.TableName))
{
<tr>
<td>
<a asp-page="/Tables/Index" asp-route-id="#tableItem.Id" asp-page-handler="LoadTable"><span class="glyphicon glyphicon-list-alt"></span> #tableItem.TableName</a>
</td>
<td>
#tableItem.TableComment
</td>
<td>
#tableItem.TableStereotype
</td>
</tr>
}
</table>
}
<hr />
<h4 class="h4-bold">View</h4>
#if (Model.PdModel.FirstOrDefault().pdViews.Count == 0)
{
#:Model doesn't contain any view
}
else
{
<table class="table table-striped">
<thead>
<th>Name</th>
<th>Description</th>
</thead>
#foreach (var viewitem in Model.PdModel.FirstOrDefault().pdViews.OrderBy(x => x.ViewName))
{
<tr>
<td><a asp-page="/Views/index" asp-page-handler="LoadView" asp-route-id="#viewitem.ID"><i class="glyphicon glyphicon-search"></i> #viewitem.ViewCode</a></td>
<td>#viewitem.ViewComment</td>
</tr>
}
</table>
}
My domain models are:
public class PdModel
{
public int Id { get; set; }
public string ModelCode { get; set; }
...
public ICollection<PdTable> PdTables { get; set; }
public ICollection<PdView> pdViews { get; set; }
}
public class PdTable
{
public int Id { get; set; }
public int ModelId { get; set; }
public string ModelCode { get; set; }
public string TableCode { get; set; }
...
[ForeignKey("ModelId")]
public virtual PdModel PdModels { get; set; }
}
public class PdView
{
public int ID { get; set; }
public string ModelCode { get; set; }
public int ModelID { get; set; }
public string ViewCode { get; set; }
...
[ForeignKey("ModelID")]
public virtual PdModel PdModel { get; set; }
}
My method is:
public PaginatedList<PdModel> PdModel { get; set; }
public async Task OnGetLoadModelAsync(int id, int? pageIndex)
{
IQueryable<PdModel> PdModelsQuer = _context.PdModel.Where(x => x.Id == id)
.Include(x => x.PdTables)
.Include(x => x.pdViews)
PdModel = await PaginatedList<PdModel>.CreateAsync(PdModelsQuer, pageIndex ?? 1, 3);
}
Not the best solution, but try this approach instead: you can create separate tables for each item and then link pagination to each table
Not sure if you have found a solution yet, but I like using this library
https://www.nuget.org/packages/X.PagedList.Mvc.Core/
To paginate different models, just create a viewmodel containing your IPagedList objects.
Here's an example of how to set up the pagination control:
#Html.PagedListPager(
(IPagedList)Model.MyPagedListObject,
page => Url.Action("MyControllerAction", "MyController",
new
{
page,
size = Model.MyPagedListObject.PageSize
}),
PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(
new PagedListRenderOptions
{
MaximumPageNumbersToDisplay = 5,
UlElementClasses = new[] { "pagination" },
ContainerDivClasses = new[] { "pagination-container" },
LiElementClasses = new string[] { "page-item" },
PageClasses = new string[] { "page-link" }
},
new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET",
UpdateTargetId = "MyDivWrapperID"
}))
If the documentation and/or this explanation is unclear I can provide a more in depth example.

How to bind Linq Multiple models data in a View using ViewBag MVC?

I am using LINQ to join multiple model classes and pass the Linq object to View using ViewBag.
I am facing problem while repeating data or binding data
Model Properties:
public class SalesModel
{
public string CustomerName { get; set; }
public int SSN { get; set; }
public int LicenseId { get; set; }
public int Age { get; set; }
public string City { get; set; }
//Vehicle Sales
public DateTime? SaleDate { get; set; }
public int CustomerId { get; set; }
public int SelecteModle { get; set; }
}
public ActionResult CreateVehicleSalesView()
{
var make = objVehicleContext.VehicleMakes;
SalesModel objSalesModle = new SalesModel()
{
MakesList = new SelectList(make, "MakeId", "Make")
};
VehicleDataContext objDataContext = new VehicleDataContext();
var vehcileSalesDetails = from VS in objDataContext.Vehiclesales
join VModel in objDataContext.VehicleModels on VS.ModelId equals VModel.ModelId
join Cus in objDataContext.Customers on VS.customerId equals Cus.customerId
join VMake in objDataContext.VehicleMakes on VModel.MakeId equals VMake.MakeId
select new
{
Name = Cus.customerName,
age = Cus.Age,
city = Cus.City,
licenseId = Cus.LicesnseId,
make = VMake.Make,
model = VModel.Model,
year = VModel.Year,
saleDate = VS.SaleDate
};
ViewBag.vehicleSalesDetails = vehcileSalesDetails;
return View(objSalesModle);
}
View:
I have problem while binding data, How to call Linq column names in a view?
<table>
<tr>
<td>Name</td>
<td>Age</td>
<td>City</td>
<td>Make</td>
<td>Model</td>
<td>Year</td>
<td>Sale Date</td>
</tr>
#foreach (var v in ()ViewBag.vehicleSalesDetails)
{
<tr>#v.Name</tr>
<tr>#v.Age</tr>
<tr>#v.City</tr>
<tr>#v.Model</tr>
<tr>#v.Year</tr>
<tr>#v.SaleDate</tr>
}
</table>
Viewbag has a dynamic construction and I don't recommend to return your object in viewbag. Maintanence is diffucult with dynamics.
You can either add other properties to your SalesModel or create new model to return view like VehicleSalesDetailModel. I recommend to create a new model like:
public class SalesModel
{
public string Name { get; set; }
//Change XXX with Make's type
public XXX Make {get;set;}
public int LicenseId { get; set; }
public int Age { get; set; }
public string City { get; set; }
//Vehicle Sales
public DateTime? SaleDate { get; set; }
public int Year{ get; set; }
}
And in your action:
public ActionResult CreateVehicleSalesView()
{
var make = objVehicleContext.VehicleMakes;
SalesModel objSalesModle = new SalesModel()
{
MakesList = new SelectList(make, "MakeId", "Make")
};
VehicleDataContext objDataContext = new VehicleDataContext();
VehicleSalesDetailModel vehcileSalesDetails = from VS in objDataContext.Vehiclesales
join VModel in objDataContext.VehicleModels on VS.ModelId equals VModel.ModelId
join Cus in objDataContext.Customers on VS.customerId equals Cus.customerId
join VMake in objDataContext.VehicleMakes on VModel.MakeId equals VMake.MakeId
select new VehicleSalesDetailModel
{
Name = Cus.customerName,
Age = Cus.Age,
City = Cus.City,
LicenseId = Cus.LicesnseId,
Make = VMake.Make,
Model = VModel.Model,
Year = VModel.Year,
SaleDate = VS.SaleDate
};
return View(vehcileSalesDetails);
}
I solved my problem.
public class VehiclesSaveAndDetails
{
public SalesModel _salesModle { get; set; }
public IEnumerable< SalesDetailsTable> _SalesDetailsTable { get; set; }
}
public ActionResult VehicleSaveAndDetails()
{
var make = objVehicleContext.VehicleMakes;
SalesModel objSalesModle = new SalesModel()
{
MakesList = new SelectList(make, "MakeId", "Make")
};
VehicleDataContext objDataContext = new VehicleDataContext();
IEnumerable<SalesDetailsTable> vehcileSalesDetails = from VS in objDataContext.Vehiclesales
join VModel in objDataContext.VehicleModels on VS.ModelId equals VModel.ModelId
join Cus in objDataContext.Customers on VS.customerId equals Cus.customerId
join VMake in objDataContext.VehicleMakes on VModel.MakeId equals VMake.MakeId
select new SalesDetailsTable
{
CustomerName = Cus.customerName,
Age = Cus.Age,
City = Cus.City,
LicenseId = Cus.LicesnseId,
MakeName = VMake.Make,
ModelName = VModel.Model,
// = VModel.Year,
SaleDate = VS.SaleDate
};
VehiclesSaveAndDetails obj = new VehiclesSaveAndDetails();
obj._salesModle = objSalesModle;
obj._SalesDetailsTable = vehcileSalesDetails;
return View(obj);
}
MyView.
#model MvcApplication1.Models.VehiclesSaveAndDetails
#{
ViewBag.Title = "VehicleSaveAndDeatils";
}
<h2>VehicleSaveAndDeatils</h2>
<script src="#Url.Content("~/Scripts/jquery-1.12.4.js")" type="text/javascript"></script>
<script src="~/Scripts/jquery-1.12.4.js"></script>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
//Dropdownlist Selectedchange event
$('#ddlMake').change(function () {
// $("#ddlModel").empty();
$.ajax({
type: "POST",
url: "/iRateBook/FillModel",
dataType: "json",
traditional: true,
data: { makeId: $(this).val() },
success: function (data) {
//alert("hello"+data.Model[0]);
$("#ddlModel").empty();
$.each(data, function (i, data) { // bind the dropdown list using json result
$('<option>',
{
value: data.ModelId,
text: data.Model
}).html(data.CityName).appendTo("#ddlModel");
});
},
error: function (ex) {
alert('Failed to retrieve states.' + ex);
}
});
return false;
})
});
</script>
#{
ViewBag.Title = "CreateVehicleSalesView";
}
<h2>CreateVehicleSalesView</h2>
#using (Html.BeginForm("SaveVehcileSales", "iRateBook"))
{
<table>
<tr>
<td>Customer Name: </td>
<td>#Html.TextBoxFor(m => m._salesModle.CustomerName) </td>
</tr>
<tr>
<td>SSN</td>
<td>#Html.TextBoxFor(m => m._salesModle.SSN)</td>
</tr>
<tr>
<td>License Number</td>
<td>#Html.TextBoxFor(m => m._salesModle.LicenseId)</td>
</tr>
<tr>
<td>Age:</td>
<td>#Html.TextBoxFor(m => m._salesModle.Age)</td>
</tr>
<tr>
<td>City :</td>
<td>#Html.TextBoxFor(m => m._salesModle.City)</td>
</tr>
<tr>
<td>Select Make:</td>
<td>
#Html.DropDownListFor(m => m._salesModle.SelectedMake, Model._salesModle.MakesList, new
{
#id = "ddlMake"
})
</td>
</tr>
<tr>
<td>Select Model</td>
<td>#Html.DropDownListFor(m => m._salesModle.SelecteModle, new List<SelectListItem>(), new { #id = "ddlModel" })</td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Save" /> </td>
</tr>
</table>
<br />
<br />
<table>
<tr>
<td>Name</td>
<td>Age</td>
<td>City</td>
<td>Make</td>
<td>Model</td>
<td>Sale Date</td>
</tr>
#foreach (var v in Model._SalesDetailsTable)
{
<tr>
<td>#v.CustomerName</td>
<td>#v.Age</td>
<td>#v.City</td>
<td>#v.MakeName</td>
<td>#v.ModelName</td>
<td>#v.SaleDate</td>
</tr>
}
</table>
}

MVC Controllers get value of 'Checkboxlist'

I'm probably a idiot here but I'm having problems getting the value of whether or not a checkbox is checked/selected or not. Here's what I've got so far:
In my Model:
public IEnumerable<SelectListItem> Insurers
{
get
{
var list = new List<SelectListItem>();
string zInsurersList = "Age UK,Be Wiser,Call Connection,Churchill,Sainsbury's,Direct Line,Hastings Direct,LV=,Nationwide,RIAS,Swinton";
string[] zInsurers = zInsurersList.Split(',');
foreach (string aInsurer in zInsurers)
{
list.Add(new SelectListItem() { Text = aInsurer, Value = aInsurer, Selected=false});
}
return list;
}
}
}
And my view:
#foreach (var insurer in #Model.Insurers)
{
var zInsurer = insurer.Text;
var zValue = insurer.Value;
<tr>
<td style="width: 120px; height: 35px;"><span id="#zInsurer">#zInsurer</span></td>
<td style="width: 40px; height: 35px;"><input id="#zInsurer" type="checkbox" name="#zInsurer"></td>
</tr>
}
So in my controller I'm trying to loop the list and get the value of whether or not the user has selected the option:
foreach (var item in model.Insurers)
{
//if (item.GetType() == typeof(CheckBox))
//string controlVal = ((SelectListItem)item).Selected.ToString();
zInsurers = zInsurers + item.Text + " " + ((SelectListItem)item).Selected.ToString() + "<br/>";
}
But the value always returns false.
Could someone spare a few mins to highlight my stupidity please?
Thanks,
Craig
There are a lot of ways to do it. I normally add String Array in model to collect selected values.
public string[] SelectedInsurers { get; set; }
<input type="checkbox" name="SelectedInsurers" value="#insurer.Value" />
Here is the sample code -
MyModel
public class MyModel
{
public string[] SelectedInsurers { get; set; }
public IEnumerable<SelectListItem> Insurers
{
get
{
var list = new List<SelectListItem>();
string zInsurersList = "Age UK,Be Wiser,Call Connection,Churchill,Sainsbury's,Direct Line,Hastings Direct,LV=,Nationwide,RIAS,Swinton";
string[] zInsurers = zInsurersList.Split(',');
foreach (string aInsurer in zInsurers)
{
list.Add(new SelectListItem { Text = aInsurer, Value = aInsurer, Selected = false });
}
return list;
}
}
}
Action Methods
public ActionResult Index()
{
return View(new MyModel());
}
[HttpPost]
public ActionResult Index(MyModel model)
{
return View();
}
View
#using (Html.BeginForm())
{
foreach (var insurer in #Model.Insurers)
{
<input type="checkbox" name="SelectedInsurers" value="#insurer.Value" /> #insurer.Text<br/>
}
<input type="submit" value="Post Back" />
}
Result
Firstly, your property Insurers should not be IEnumerable<SelectListItem> (tha'ts for binding a collection to a dropdownlist), and in any case, that kind of logic does not belong in a getter (and whats the point of creating a comma delimited string and then splitting it? - just create an array of strings in the first place!). Its not really clear exactly what you trying to do, but you should be creating a view model and doing it the MVC way and making use of its model binding features
View model
public class InsurerVM
{
public string Name { get; set; }
public bool IsSelected { get; set; }
}
Controller
public ActionResult Edit()
{
// This should be loaded from some data source
string[] insurers = new string[] { "Age UK", "Be Wiser", "Call Connection" };
List<InsurerVM> model = insurers.Select(i => new InsurerVM() { Name = i }).ToList();
return View(model);
}
View
#model List<InsurerVM>
#using(Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(m => m[i].Name)
#Html.CheckBoxFor(m => m[i].IsSelected)
#Html.LabelFor(m => m.[i].IsSelected, Model[i].Name)
}
<input type="submit" value="Save" />
}
Post method
[HttpPost]
public ActionResult Edit(IEnumerable<InsurerVM> model)
{
// loop each item to get the insurer name and the value indicating if it has been selected
foreach(InsurerVM insurer in model)
{
....
}
}
In reality, Insurers would be an object with an ID and other properties so it can be identified and have a relationship with other entities.
As to why you code is not working. Your property does not have a setter so nothing that posted back could be bound anyway. All the method is doing is initializing your model then calling the getter which creates a new IEnumerable<SelectListItem> (identical to the one you sent to the view in the first place). Not that it would have mattered anyway, your checkboxes have name attributes name="Age_UK", name=Be_Wiser" etc which have absolutely no relationship to your model so cant be bound
That is because the modelbinding can't process your values.
You should look into model binding.
Try something like this:
#for (var countInsurer = 0; Model.Insurers.Count > countInsurer++)
{
var zInsurer = insurer.Text;
var zValue = insurer.Value;
<tr>
<td style="width: 120px; height: 35px;"><span id="#zInsurer">#zInsurer</span></td>
<td style="width: 40px; height: 35px;">#Html.CheckBoxFor(m=> Model.Insurers[countInsurer], new {name = zInsurer})</td>
</tr>
}
#for(int i = 0; i < Model.List.Count; i++)
{
#Html.CheckBoxFor(m => Model.List[i].IsChecked, htmlAttributes: new { #class = "control-label col-md-2" })
#Model.List[i].Name
#Html.HiddenFor(m => Model.List[i].ID)
#Html.HiddenFor(m => Model.List[i].Name)
<br />
}
in controller
StringBuilder sb = new StringBuilder();
foreach (var item in objDetail.List)
{
if (item.IsChecked)
{
sb.Append(item.Value + ",");
}
}
ViewBag.Loc = "Your preferred work locations are " + sb.ToString();
I Get Module And Right from Module and Rights Table How to Send All Data To RoleRight Table All Checkbox value
public class RoleRightModel
{
public ModuleModel _ModuleModel { get; set; }
public RightsModel _RightsModel { get; set; }
public RolesModel _RolesModel { get; set; }
public List<ModuleModel> _ModuleModelList { get; set; }
public List<RightsModel> _RightsModelList { get; set; }
public List<RolesModel> _RolesModelList { get; set; }
public List<RoleRightModel> _RoleRightModelList { get; set; }
public int RoleRightID { get; set; }
public int RoleID { get; set; }
public int ModuleID { get; set; }
public int FormMode { get; set; }
public int RightCode { get; set; }
public bool? RowInternal { get; set; }
public byte? IsAuthorised { get; set; }
public int? CreationID { get; set; }
public DateTime? CreationDate { get; set; }
public int? LastModificationID { get; set; }
public DateTime? LastModificationDate { get; set; }
public byte? RowStatus { get; set; }
public string RoleName { get; set; }
}
Razor
#foreach(var item in Model._ModuleModelList.Where(x => x.Level == 1))
{
<ul style="display: block;">
<li><i class="fa fa-plus"></i>
<label>
#if (item.Level == 1)
{
<input id="node-0-1" data-id="custom-1" type="checkbox" name="Module" value="#item.ModuleID"#(Model._ModuleModel.ModuleID)? "checked":"">
#item.ModuleName
}
</label>
#foreach (var lavel1 in Model._ModuleModelList.Where(x => x.ParentModuleID == item.ModuleID))
{
<ul>
<li><i class="fa fa-plus"></i>
<label>
<input id="node-0-1-1" data-id="custom-1-1" type="checkbox" name="Module" value="#lavel1.ModuleID"#(Model._ModuleModel.ModuleID)? "checked":"">
#lavel1.ModuleName
</label>
#foreach (var lavel2 in Model._ModuleModelList.Where(x => x.ParentModuleID == lavel1.ModuleID))
{
<ul>
<li><i class="fa fa-plus"></i>
<label>
<input id="node-0-1-1-1" data-id="custom-1-1-1" type="checkbox" name="Module" value="#lavel2.ModuleID"#(Model._ModuleModel.ModuleID)? "checked":"">
#lavel2.ModuleName
</label>
#foreach (var lavel3 in Model._RightsModelList.Where(x => x.ModuleId == lavel2.ModuleID))
{
<ul>
<li>
<label>
<input id="node-0-1-1-1-1" data-id="custom-1-1-1-1" type="checkbox" name="Right" value="#lavel3.RightID"#(Model._RightsModel.RightID)? "checked":"">
#lavel3.RightName
</label>
</li>
</ul>
}
</li>
</ul>
}
</li>
</ul>
}
</li>
</ul>
}

ViewModel is partially null after POST

I have an MVC 4 App where i have a ViewModel which has a couple of collections. During a POST the collections are null but the other fields are populated. Code attached please help.
View Model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BAQueryTool.Models
{
public class QueryDefinition
{
[Key]
public int ID { get; set; }
[Display(Name = "Query Name")]
[MaxLength(32)]
[Required(ErrorMessage = "Query name is required.")]
public string Name { get; set; }
[Display(Name = "Query String")]
[Required(ErrorMessage = "Query string is required.")]
[DataType(DataType.MultilineText)]
[MaxLength(8192)]
public string QueryString { get; set; }
[NotMapped]
[Display(Name = "Query String")]
[MaxLength(175)]
public string QueryStringShort
{
get
{
string s = string.Empty;
if (this.QueryString != null)
{
s = this.QueryString.Trim();
if (s.Length >= 172)
{
return this.QueryString.Substring(0, 172) + "...";
}
}
return s;
}
}
[Display(Name = "Query Parameters")]
public virtual ICollection<QueryParameter> QueryParameters { get; set; }
}
public class RunQueryDefinition
{
public QueryDefinition QueryDefinition { get; set; }
[Display(Name = "Run Query Parameters")]
public virtual ICollection<RunQueryParameter> RunQueryParameters { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BAQueryTool.Models
{
public enum ParameterDataType
{
Date, String
}
public class QueryParameter
{
[Key]
public int ID { get; set; }
public int QueryDefinitionID { get; set; }
[Display(Name = "Parameter Name")]
[Required(ErrorMessage = "Parameter name is required.")]
[MaxLength(32)]
public string Name { get; set; }
[Display(Name = "Parameter Type")]
[Required(ErrorMessage = "Parameter name is required.")]
public ParameterDataType DataType { get; set; }
}
public class RunQueryParameter : QueryParameter
{
[Display(Name = "Parameter Value")]
[Required(ErrorMessage = "Parameter name is required.")]
public string Value { get; set; }
}
}
Controller
` `// GET: /QueryDefinition/Run/5
public ActionResult Run(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
QueryDefinition querydefinition = db.QueryDefinitions.Find(id);
if (querydefinition == null)
{
return HttpNotFound();
}
RunQueryDefinition runQueryDefinition = new RunQueryDefinition();
runQueryDefinition.QueryDefinition = querydefinition;
runQueryDefinition.RunQueryParameters = new List<RunQueryParameter> { };
foreach (var param in querydefinition.QueryParameters)
{
RunQueryParameter rqp = new RunQueryParameter();
rqp.ID = param.ID;
rqp.QueryDefinitionID = param.QueryDefinitionID;
rqp.Name = param.Name;
rqp.DataType = param.DataType;
rqp.Value = Convert.ToString(DateTime.Now.ToShortDateString());
runQueryDefinition.RunQueryParameters.Add(rqp);
}
return View(runQueryDefinition);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Run(RunQueryDefinition parameterList)
{
DateTime BeginDate;
DateTime EndDate;
try
{
//QueryDefinition querydefinition = db.QueryDefinitions.Find(id);
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
}
catch (RetryLimitExceededException)
{
//Log the error
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View();
}
View
#model BAQueryTool.Models.RunQueryDefinition
#{
ViewBag.Title = "Run Query";
}
<h2>Run Query Definition '#Html.DisplayFor(model => model.QueryDefinition.Name)'</h2>
#using (Html.BeginForm("Run", "QueryDefinition", FormMethod.Post, null))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.RunQueryParameters)
</dt>
<dd>
<table class="table">
<tr>
<th>Parameter Name</th>
<th>Parameter Data Type</th>
<th>Parameter Value</th>
</tr>
#foreach (var item in Model.RunQueryParameters)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.DataType)
</td>
<td>
#Html.EditorFor(modelItem => item.Value)
</td>
</tr>
}
</table>
</dd>
</dl>
<div class="form-group">
<div class="col-md-offset-1 col-md-10">
<input type="submit" value="Run Query" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The main class is the QueryDefinition class. There is a Index page which lists out all the query definitions. When the user clicks on Run link the Run page is generated and populated with the QueryDefinitions for an Id. The QueryParameters Collection is also populated as well as the RunQueryParameters collection. When the user enters a value for the Column Value and clicks on Run Query a POST occurs. In Debug I noticed that the RunQueryDefinitions parameterList parameter was not fully populated, particularly the collections QueryParameters and RunQueryParameters.
Any suggestion ?
Do not use foreach loop, use for loop instead so that indexed values of collection can get posted:
#for(int i = 0; i < Model.RunQueryParameters.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.RunQueryParameters[i].Name)
</td>
<td>
#Html.DisplayFor(modelItem => Model.RunQueryParameters[i].DataType)
</td>
<td>
#Html.EditorFor(modelItem => Model.RunQueryParameters[i].Value)
</td>
</tr>
}
See how model binding works in this article.

Resources