Passing multiple models from one view to a controller - asp.net

If I google for "multiple models in one view" I can only find results about how I can pass models to a view. But I'm interested in the "from view to controller" direction.
So let's assume:
I have 3 different forms and 1 table (WebGrid) in one view.
And I have one model per form and one model for the table.
Let my model classes be ModelF1, ModelF2, ModelF3 and ModelT.
All the examples I have seen until now uses a container ViewModel like
class MyViewModel {
ModelF1 inst1,
ModelF2 inst2,
ModelF3 inst3,
ModelT instT
}
And then they pass it between view <-> controller in 2 ways.
But I want to catch my models this way without using a viewmodel:
class MyController {
ActionResult Index() {
return new View(modelF1Instance, modelF2Instance, modelF3Instance, modelTInstance);
}
ActionResult Form1Action(ModelF1 inst1, ModelT instT) {
// process models after a form1 submit
}
ActionResult Form2Action(ModelF2 inst2, ModelT instT) {
// process models after a form2 submit
}
ActionResult Form3Action(ModelF3 inst3, ModelT instT) {
// process models after a form3 submit
}
}
Is this possible without parsing the whole form elements in a CustomBinder?

Firstly you can only send a strongly typed view model back to your view using
return View(model);
View is a method on the base class, not a class to be instantiated with return new View(...
Then to your real question: Yes you can do this, but using a top level ViewModel which contains your different form items is far, far easier in the majority of use cases. The main problem the top level container ViewModel handles really well is value persistence and server-side validation and error messages between round trips.
If you are only worried about the perception of inefficiency from creating a top level ViewModel container, then don't. This is far more efficient than all the workarounds you may have to put in place in order to get well behaved forms working without the top level ViewModel.
There is some example code below. The code below should demonstrate that using models contained within the top level ViewModel is just simpler and neater: some of the forms deliberately don't round trip some of the state. Note the usage of HiddenFor and ModelState.Clear which are both related to what you are trying to do, but even these won't persist the value for inst4.Name for Form4Submit. The various options explored are:
Use a query parameter to denote which form is being posted
Use a different form name, but still with the view model.
Use a redirect-only Action for the form (send new instances, and only part of the viewmodel)
Use a mixture of the above
public class TestController : Controller
{
//
// GET: /Test/
[System.Web.Mvc.HttpGet]
public ActionResult Index(string msg = null)
{
var model = new MyViewModel
{
Inst1 = new ModelF1 { Name = "Name of F1" },
Inst2 = new ModelF2 (),
InstT = new ModelT {Name = "Name of T"},
PostNumber = 0,
Message = msg
};
return View(model);
}
[System.Web.Mvc.HttpPost]
public ActionResult Index(MyViewModel model, int option = 1)
{
// process models after a form1/2 submit
model.Message = "You posted " +
((option == 1) ? model.Inst1.Name : model.Inst2.Name)
+ " to Index for "
+ ((option == 1) ? "inst1" : "inst2");
model.PostNumber ++;
// This, and the hiddenFor are required to allow us to update the PostNumber each time
ModelState.Clear();
return View(model);
}
[System.Web.Mvc.HttpPost]
public ActionResult Form2Submit(MyViewModel model)
{
// process models after a form2 submit
model.Message = "You posted " + model.Inst2.Name + " to Form2Submit";
model.PostNumber++;
ModelState.Clear();
return View("Index", model);
}
[System.Web.Mvc.HttpPost]
public ActionResult Form3Submit(ModelF3 inst3, ModelT instT)
{
// process models after a form3 submit
var n = instT.Name;
var msg = "You posted " + inst3.Name + ", " + n + " to Form3Submit";
// We no longer have access to pass information back to the view, so lets redirect
return RedirectToAction("Index", new { msg = msg });
}
[System.Web.Mvc.HttpPost]
public ActionResult Form4Submit(ModelF4 inst4, MyViewModel model)
{
// process models after a form4 submit
var n = model.InstT.Name;
model.Message = "You posted " + inst4.Name + ", " + n + " to Form4Submit";
model.PostNumber++;
ModelState.Clear();
return View("Index", model);
}
public class MyViewModel
{
public int PostNumber { get; set; }
public string Message { get; set; }
public ModelF1 Inst1 { get; set; }
public ModelF2 Inst2 { get; set; }
public ModelT InstT { get; set; }
}
public class ModelBase { public string Name { get; set; } }
public class ModelF1 : ModelBase {}
public class ModelF2 : ModelBase { }
public class ModelF3 : ModelBase { }
public class ModelF4 : ModelBase { }
public class ModelT : ModelBase { }
}
Then for the multi-form view:
#using MyWebSite.Controllers;
#model TestController.MyViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<p>
#Html.Raw(Model.PostNumber) : #Html.Raw(Model.Message)
</p>
<p>
#Html.LabelFor(m => Model.InstT) : <br />
#Html.DisplayFor(m => Model.InstT)
</p>
<div>
<p>Default form submit</p>
#using (Html.BeginForm())
{
<div>
#Html.HiddenFor(m => m.PostNumber)
#Html.LabelFor(m => Model.Inst1.Name)
#Html.TextBoxFor(m => Model.Inst1.Name)
</div>
<input type="submit" value="Submit Index" />
}
</div>
<div>
<p>Use a parameter to denote the form being posted</p>
#using (Html.BeginForm("Index", "Test", new { option = 2 }))
{
<div>
#* Omitting these will not persist them between trips
#Html.HiddenFor(m => Model.Inst1.Name)
#Html.HiddenFor(m => Model.InstT.Name)*#
#Html.HiddenFor(m => m.PostNumber)
#Html.LabelFor(m => Model.Inst2.Name)
#Html.TextBoxFor(m => Model.Inst2.Name)
</div>
<input type="submit" value="Submit with option parameter" />
}
</div>
<div>
<p>Use a different form name, but still use the ViewModel</p>
#using (Html.BeginForm("Form2Submit", "Test"))
{
<div>
#Html.HiddenFor(m => Model.Inst1.Name)
#Html.HiddenFor(m => Model.InstT.Name)
#Html.HiddenFor(m => m.PostNumber)
#Html.LabelFor(m => Model.Inst2.Name)
#Html.TextBoxFor(m => Model.Inst2.Name)
</div>
<input type="submit" value="Submit F2" />
}
</div>
<div>
<p>Submit with a redirect, and no ViewModel usage.</p>
#using (Html.BeginForm("Form3Submit", "Test"))
{
var inst3 = new TestController.ModelF3();
<div>
#Html.HiddenFor(m => Model.InstT.Name)
#Html.LabelFor(m => inst3.Name)
#Html.TextBoxFor(m => inst3.Name)
</div>
<input type="submit" value="Submit F3" />
}
</div>
<div>
<p>Submit with a new class, and the ViewModel as well.</p>
#using (Html.BeginForm("Form4Submit", "Test"))
{
var inst4 = new TestController.ModelF4();
<div>
#Html.HiddenFor(m => Model.Message)
#Html.HiddenFor(m => Model.PostNumber)
#Html.HiddenFor(m => Model.Inst1.Name)
#Html.HiddenFor(m => Model.Inst2.Name)
#Html.HiddenFor(m => Model.InstT.Name)
#Html.LabelFor(m => inst4.Name)
#Html.TextBoxFor(m => inst4.Name)
</div>
<input type="submit" value="Submit F4" />
}
</div>
</body>
</html>

Related

ASP.NET List<SelectListItem> is passing null to controller

I have a form, with radiobuttons. After selecting one of them, in [POST] method, the 'Companies' List Count is still 0. Do you have any idea what causes the problem?
Controller:
// GET: Commission/Create
public ActionResult Create()
{
CommissionMVCCreateModel commission = new CommissionMVCCreateModel();
List<CompanyMVCModel> companies = SQLiteDataAccess.LoadCompanies();
commission.Companies = companies.Select(x => new SelectListItem { Text = x.CompanyName, Value = x.Id.ToString() }).ToList();
return View(commission);
}
// POST: Commission/Create
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Create(CommissionMVCCreateModel commissionModel)
{
try
{
if(ModelState.IsValid)
{
}
// TODO: Add insert logic here
return View();
}
catch
{
return View();
}
}
Model:
public class CommissionMVCCreateModel
{
public List<SelectListItem> Companies { get; set; } = new List<SelectListItem>();
...
...
}
View:
<form>
...
...
#Html.LabelFor(model => model.Companies, htmlAttributes: new { #class = "control-label" })
<div class="btn-group-vertical">
#foreach (var company in Model.Companies)
{
<label class="btn btn-primary col-md-offset-2 col-md-5 ">
<input type="radio" name="company" id="#company.Value" value="#company.Value"/>
#company.Text
</label>
}
</div>
...
...
</form>
In the form i have also part for creating new Company, and it's values are passed correctly. The only problem i have is with this SelectListItem. I tried also using SelectList, but the result was the same.

EditorForMany not working for objects deeper than 1 level

I have an example asp.net mvc5 program in which I'm trying to build a payment model with many levels of partials added to make a complete object. In this example, I am using generic data. I have a top level 'testing', to which you can add multiple 'A1' objects, and to that you can add multiple 'B2' objects.
The form uses ajax and jqueryto allow the person to add data on the fly, which is then submitted all at once when the submit button is pressed.
I found an html helper made by Matt Lunn that does an editorForMany. It works very well, adds all my info to the web page, but it will never post back a model that is deeper than 2 levels(top, with a1's attached).
I can get the entire model to build on my page. It looks appropriate, but when I post back, nothing under A1 shows up. I can add as many 'A1's as I want. If I change the code and put 'B2's directly under testing, that will work, but nothing will add under the 'A1's as I have it.
Here is my code. I apologize for the formatting and the length of this post.
MVC helper
public static MvcHtmlString EditorForMany<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable<TValue>>> propertyExpression, Expression<Func<TValue, string>> indexResolverExpression = null, bool includeIndexField = true) where TModel : class
{
var items = propertyExpression.Compile()(html.ViewData.Model);
var htmlBuilder = new StringBuilder();
var htmlFieldName = ExpressionHelper.GetExpressionText(propertyExpression);
var htmlFieldNameWithPrefix = html.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName);
Func<TValue, string> indexResolver = null;
if (indexResolverExpression == null)
{
indexResolver = x => null;
}
else
{
indexResolver = indexResolverExpression.Compile();
}
foreach (var item in items)
{
var dummy = new { Item = item };
var guid = indexResolver(item);
var memberExp = Expression.MakeMemberAccess(Expression.Constant(dummy), dummy.GetType().GetProperty("Item"));
var singleItemExp = Expression.Lambda<Func<TModel, TValue>>(memberExp, propertyExpression.Parameters);
if (String.IsNullOrEmpty(guid))
{
guid = Guid.NewGuid().ToString();
}
else
{
guid = html.AttributeEncode(guid);
}
if (includeIndexField)
{
htmlBuilder.Append(_EditorForManyIndexField<TValue>(htmlFieldNameWithPrefix, guid, indexResolverExpression));
}
htmlBuilder.Append(html.EditorFor(singleItemExp, null, String.Format("{0}[{1}]", htmlFieldName, guid)));
}
MvcHtmlString m1 = new MvcHtmlString(htmlBuilder.ToString());
return m1;
}
testing Controller
public class testingController : Controller
{
// GET: testing
public ActionResult startTest()
{
var model = new testing();
return View(model);
}
[HttpPost]
public ActionResult startTest([Bind] testing model)
{
if (ModelState.IsValid)
{
var r = 1;
}
return View(model);
}
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult addA1()//current running test
{
var model = new testing();
model.aas.Add(new A1());
return View(model);
}
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult addB2()//current running test
{
var model = new A1();
model.bbs.Add(new B2());
return View(model);
}
}
model class
public class testing
{
public string name { get; set; }
public List<A1> aas { get; set; }
public testing()
{
aas = new List<A1>();
}
}
public class A1
{
public string aName { get; set; }
public List<B2> bbs { get; set; }
public A1()
{
bbs = new List<B2>();
}
}
public class B2
{
public string bName { get; set; }
public B2() { }
}
startTest.cshtml
#model proofOfConceptPaymentBuilder.Models.testing
#{
ViewBag.Title = "startTest";
}
#section Scripts
{
<script>
jQuery(document).ready(function ($) {
$('#add-bbs').on('click', function () {
jQuery.get('/testing/addB2').done(function (html) {
$('#bbsList').append(html);
});
});
$('#add-aas').on('click', function () {
jQuery.get('/testing/addA1').done(function (html) {
$('#aasList').append(html);
});
});
});
function alertSomething() {
alert('something');
jQuery.get('/testing/addB2').done(function (html) {
$('#bbsList').append(html);
});
};
</script>
}
#using (Html.BeginForm())
{
<h2>Create</h2>
#Html.EditorFor(x => x)
<input type="submit" />
}
EditorTemplates
(testing editor template)
#model proofOfConceptPaymentBuilder.Models.testing
<div class="form-group">
#Html.LabelFor(x => x.name)
#Html.EditorFor(x => x.name)
</div>
<div class="form-group">
<div id="aasList">
#Html.EditorFor(x => x.aas)
</div>
<input type="button" id="add-aas" value="add aas" />
<input type="button" id="delete-testing" value="delete test" />
</div>
(a1 editor template)
#model proofOfConceptPaymentBuilder.Models.A1
<div class="form-group">
#Html.LabelFor(x => x.aName)
#Html.EditorFor(x => x.aName)
</div>
<div class="form-group">
<div id="bbsList">
#Html.EditorForMany(x => x.bbs)
</div>
<input type="button" id="add-bbs" value="add bss" onclick="alertSomething()"/>
<input type="button" id="delete-aas" value="delete ass" />
</div>
(b2 editor template)
#model proofOfConceptPaymentBuilder.Models.B2
<div class="form-group">
#Html.LabelFor(x => x.bName)
#Html.EditorFor(x => x.bName)
</div>
<div>
<input type="button" id="delete-bss" value="delete bbs" />
</div>
addA1.cshtml
#model proofOfConceptPaymentBuilder.Models.testing
#{
Layout = null;
}
#Html.EditorForMany(x => x.aas)
addB2.cshtml
#model proofOfConceptPaymentBuilder.Models.A1
#{
Layout = null;
}
#Html.EditorForMany(x => x.bbs)
Ok, so I'm sorry for the formatting. I'm kinda new to the formatting here. I had to manually indent my code for it to show up in code blocks.
I also stumbled upon this problem and, given the number of questions I have found here in StackOverflow dealing with similar problems, I have created a .NET Core library to solve exactly this. It is called DynamicVML (Dynamic View-Model Lists) and you can get it with NuGet.
It is basically a list templating engine for ASP.NET Core, that you can use to display lists of view models of any depth.
You can use it like this:
#Html.ListEditorFor(x => x.Addresses,
Url.Action("AddAddress"), // the action in your controller that creates views
"Add new address", // some text for the "add new item button" in your form
listContainerTemplate: "viewThatWrapsTheList",
listTemplate: "viewForTheList",
itemContainerTemplate: "viewThatWrapsYourViewModel",
ItemTemplate: "viewForYourViewModel")
Now, you do not actually have to specifiy all of this. If you want you can do just
#Html.ListEditorFor(x => x.Addresses, Url.Action("AddAddress"), "Add new address")
And it will guess all the rest.
It will support nesting with any depth, as it was the core of the question.

ASP.NET code snippit to query database for unique field value

I'm trying to create custom remote data annotation to check for unique values.
So far I have:
[Remote("checkForUniqueSpeciesName", "Create", ErrorMessage = "A Species by that name already exists.")]
public string SpeciesName { get; set; }
and
public ActionResult checkForUniqueSpeciesName(string species_name)
{
bool is_unique = ........
return Json(is_unique, JsonRequestBehavior.AllowGet);
}
To be honest, I don't really understand how this works, I'm just trying to follow examples found on the web. I guess checkForUniqueSpeciesName is called when the form is submitted, and the method returns true or false. Is there something I need to put in the view to make the validation message come up, such as?
#Html.ValidationMessageFor(model => model.SpeciesName, "", new { #class = "text-danger" })
Do I need that?
Model Species.cs:
public class Species
{
[Key]
public int SpeciesId { get; set; }
[Display(Name = "Species")]
[Required(ErrorMessage = "You must enter a species name.")]
[Remote("CheckForUniqueSpeciesName", "Create", ErrorMessage = "A Species by that name already exists.")]
public string SpeciesName { get; set; }
}
Controller SpeciesController.cs:
namespace Gators3.Controllers
{
public class SpeciesController : Controller
{
private GatorsContext db = new GatorsContext();
// GET: Species
public ActionResult Index()
{
return View(db.Species.ToList());
}
// GET: Species/Create
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "SpeciesId,SpeciesName")] Species species)
{
if (ModelState.IsValid)
{
db.Species.Add(species);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(species);
}
public ActionResult CheckForUniqueSpeciesName(string speciesName)
{
using (GatorsContext ctx = new GatorsContext())
{
bool isUnique = !ctx.Species.Any(s => s.SpeciesName == speciesName);
return Json(isUnique, JsonRequestBehavior.AllowGet);
}
}
.
.
.
.
View Views->Species->Create.cshtml:
#model Gators3.Models.Species
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Species</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.SpeciesName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SpeciesName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SpeciesName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I guess checkForUniqueSpeciesName is called when the form is
submitted, and the method returns true or false.
No, that is not the case. The [RemoteAttribute] adds some JavaScript to your page automatically that will call a method on your Controller to do some server side validation and display the result on the page without the user needing to submit the whole HTML form. i.e. The validation is invoked when you tab out of the text box, not when you click submit.
With your code, I assume your controller is named CreateController?
I'm guessing you're just missing your data access code to actually check uniqueness?
So something like this would be required:
public ActionResult CheckForUniqueSpeciesName(string speciesName)
{
using (YourEntityFrameworkDbContext ctx = new YourEntityFrameworkDbContext())
{
bool isUnique = !ctx.Species.Any(s => s.SpeciesName == speciesName);
return Json(isUnique , JsonRequestBehavior.AllowGet);
}
}
Then in your view, you just need something like this:
#Html.ValidationMessageFor(x => x.SpeciesName)
Which will display the validation message you specified in your [Remote] attribute.
By the way, just as a side note - the coding conventions/casing you've applied to some of your code won't be popular with most C# programmers (unless your team are abiding by an unusual standard) so note the formatting I've applied.
Update - I think your code needs to have the following:
[Remote("CheckForUniqueSpeciesName", "Species", ErrorMessage="A Species by that name already exists.")]

ASP.NET MVC redirect actions error with 'create' partial view on 'index' page

I'm having a problem with partial views. I have an index view of Announcements and I'm trying to add a partial view to create a new Announcement within the same page.
I can display the partial view, and submit the form to create a new record. The record gets submitted into the database, but when re-rendering the page, I get the error: Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper', {"Child actions are not allowed to perform redirect actions."} on my Html.Action statement in my index page.
I've been struggling to make this work, and have firstly changed the Html.Partial to a Html.Action statement as the controller methods weren't firing, then secondly, after I read that this error is because while rendering the page, .NET doesn't know what my redirect action is doing so automatically stops it, tried changing the Html.Action to Html.RedirectAction inside a code block, but still get the same error detailed above.
My model is quite simple:
public class Announcement
{
public Announcement()
{
AnnouncementDate = System.DateTime.Now;
}
[Key]
public int AnnouncementID { get; set; }
public string Title { get; set; }
public string Type { get; set; }
}
My Controller methods:
public ViewResult Index(string searchString, int? page)
{
var Announcements = from a in db.Announcements
select a;
if (!String.IsNullOrEmpty(searchString))
{
Announcements = Announcements.Where(s => (s.Title.ToUpper().Contains(searchString.ToUpper()) || s.AnnouncementText.ToUpper().Contains(searchString.ToUpper())));
}
Announcements = Announcements.OrderBy(s => s.Title);
int pageSize = 10;
int pageNumber = (page ?? 1);
return View(Announcements.ToPagedList(pageNumber, pageSize));
}
//
// GET: /Announcement/Create
public ActionResult Create()
{
Announcement announcement = new Announcement();
return PartialView(announcement);
}
//
// POST: /Announcement/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Announcement announcement)
{
if (ModelState.IsValid)
{
db.Announcements.Add(announcement);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(announcement);
}
Index.cshtml
#model PagedList.IPagedList<Project.Models.Announcement>
#using PagedList.Mvc;
#using PagedList;
#using (Html.BeginForm())
{
#Html.TextBox("SearchString", ViewBag.CurrentFilter as string, new { #class = "search-query", placeholder = "Search by name" })
<input type="submit" value="Search" class="btn" />
}
#item.Title
#item.Type
#Html.Action("Create"); // This is the line causing errors after I submit the Create form. Have tried changing to Html.RedirectAction
Create.cshtml:
#model Project.Models.Announcement
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.TextBoxFor(model => model.Title, new { #style = "width:250px" })
#Html.TextBoxFor(model => model.Type, new { #style = "width:250px" })
<input type="submit" value="Create" class="btn btn-small" />
}
After doing some testing locally...
You can keep
#Html.Action("Create")
However, you have to change one small thing. Define what action the POST points to in your form :)
#model Project.Models.Announcement
#using (Html.BeginForm("Create"))
{
#Html.AntiForgeryToken()
#Html.TextBoxFor(model => model.Title, new { #style = "width:250px" })
#Html.TextBoxFor(model => model.Type, new { #style = "width:250px" })
<input type="submit" value="Create" class="btn btn-small" />
}

LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression

This is my controller class
public class HomeController : Controller
{
private rikuEntities rk = new rikuEntities();
public ActionResult Index()
{
var db = new rikuEntities();
IEnumerable<SelectListItem> items = db.emp.Select(c => new
SelectListItem
{
Value = c.Id.ToString(),
Text = c.name
});
ViewBag.CategoryID = items;
return View();
}
}
this is my view
#using (Html.BeginForm("viewToController", "Home"))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>emp</legend>
<div class="editor-field">
#Html.DropDownList("CategoryID", (IEnumerable<SelectListItem>) ViewBag.Categories)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
whenever I run this program I get this error:
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression." in the statement #Html.DropDownList("CategoryID", (IEnumerable) ViewBag.Categories). i am using entity framework mechanism for databse connection. please help me to find out the error...
I would recommend you to use view models and strongly typed views instead of ViewBag. So start with defining your view model:
public class EmployeeViewModel
{
public string CategoryId { get; set; }
public IEnumerable<Employee> Categories { get; set; }
}
then in the controller populate this view model:
public class HomeController : Controller
{
public ActionResult Index()
{
var db = new rikuEntities();
var model = new EmployeeViewModel
{
Categories = db.emp.ToArray() // <-- you probably want categories here
};
return View(model);
}
}
and in the view:
#model EmployeeViewModel
#using (Html.BeginForm("viewToController", "Home"))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>emp</legend>
<div class="editor-field">
#Html.DropDownListFor(
x => x.CategoryId,
new SelectList(Model.Categories, "Id", "name")
)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Sadly EF does not know how to convert ToString() to an SQL statement.
You must, therefore, use the embedded function SqlFunctions.StringConvert.
There is no overload for int so you will need to typecast to double :-(
var items = from v in db.emp
select new SelectListItem
{
Text = c.name,
Code = SqlFunctions.StringConvert((double)c.Id)
};

Resources