I am getting values from a ViewModel into a view for form fields. In one of my DropDownList the values are correct but in another the value repeats itself instead of changing. What am I doing wrong?
ViewModel:
namespace FulfillmentPortal.ViewModels
{
public class ViewModel
{
[Required(ErrorMessage = "Please select a carrier")]
public List<Carrier> CarrierList { get; set; }
[Required(ErrorMessage = "Please select a service")]
public List<CarrierService> ServiceList { get; set; }
}
}
Controller:
public class FulfillmentController : Controller
{
private CarrierModel db = new CarrierModel();
// GET: Fulfillment
public ActionResult Index()
{
ViewModel vm = new ViewModel
{
CarrierList = db.Carriers.ToList(),
ServiceList = db.CarrierServices.ToList()
};
return View(vm);
}
}
View:
#model FulfillmentPortal.ViewModels.ViewModel
#{
ViewBag.Title = "index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="panel panel-primary">
<div class="panel-heading">REPORT OPTIONS</div>
<div class="panel-body" style="padding-left:35px;">
<form id="processForm" class="form-horizontal" action="~/Fulfillment/Report" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="sel1">Carrier:</label>
#Html.DropDownListFor(model => model.CarrierList, new SelectList(Model.CarrierList, "CarrierId", "CarrierName"), "Select a Carrier",
new { #class = "form-control", #style = "width:auto; margin-bottom:15px;" })
<label for="sel2">Carrier Services:</label>
#Html.DropDownListFor(model => model.ServiceList, new SelectList(Model.ServiceList, "Code", "WebName"), "Select a Service",
new { #class = "form-control", #style = "width:auto; margin-bottom:15px;" })
</div>
</form>
</div>
</div>
Model:
public partial class CarrierModel : DbContext
{
public CarrierModel()
: base("name=CarrierModel")
{
}
public virtual DbSet<Carrier> Carriers { get; set; }
public virtual DbSet<CarrierService> CarrierServices { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
[HttpPost]
public ActionResult Index(ViewModel viewModel)
{
if (ModelState.IsValid)
{
viewModel.CarrierList.ToList();
viewModel.ServiceList.ToList();
}
return View(viewModel);
}
This my controller now. Now my view is just erroring out. I think I am missing something or misunderstanding something.
DropDownListFor(model => model.ServiceList
This is not how this method is supposed to work, and I suspect this is the answer to your problem.
This lambda is supposed to provide a field that will hold a value that this drop down list outputs. For your case you should have two fields in the model:
public class ViewModel
...
public int CarrierId { get; set; }
public string CarrierServiceCode { get; set; }
These will hold currently selected value, on none if nothing is selected (yet). And they are supposed to be used in that lambda:
DropDownListFor(model => model.CarrierServiceCode
Alternatively you could use DropDownList() method, which does not require a field in the model, and give it a custom name that will be posted with selected value.
Your ViewModel should be as follows:
public class ViewModel
{
[Required(ErrorMessage = "Please select a carrier")]
public int CarrierId {get; set;}
[Required(ErrorMessage = "Please select a service")]
public int ServiceCode {get; set;}
public List<Carrier> CarrierList { get; set; }
public List<CarrierService> ServiceList { get; set; }
}
Then in the view:
<label for="sel1">Carrier:</label>
#Html.DropDownListFor(model => model.CarrierId, new SelectList(Model.CarrierList, "CarrierId", "CarrierName"), "Select a Carrier",
new { #class = "form-control", #style = "width:auto; margin-bottom:15px;" })
<label for="sel2">Carrier Services:</label>
#Html.DropDownListFor(model => model.ServiceCode, new SelectList(Model.ServiceList, "Code", "WebName"), "Select a Service",
new { #class = "form-control", #style = "width:auto; margin-bottom:15px;" })
Then your Index Post method should be as follows:
[HttpPost]
public ActionResult Index(ViewModel viewModel)
{
if(ModelState.IsValid)
{
// do whatever you want with `viewModel.CarrierId` and `viewModel.ServiceCode` here
}
viewModel.CarrierList = db.Carriers.ToList();
viewModel.ServiceList = db.CarrierServices.ToList();
return View(viewModel);
}
Related
I am making an MVC application. I am creating a View that uses a ViewModel and also use database entities in this view passed by the controller.
Controller:
public ActionResult AddGroup(AddGroupViewModel model)
{
ClassDeclarationsDBEntities1 entities=new ClassDeclarationsDBEntities1();
return View(entities.Subjects.ToList());
}
ViewModel:
public class AddGroupViewModel
{
[Required]
[Display(Name = "Subject")]
public string subject_name { get; set; }
[Required]
[Display(Name = "Number of Groups")]
public int qty { get; set; }
}
And finally my view:
#model List<ClassDeclarationsThsesis.Classes.Subject>
#model ClassDeclarationsThsesis.Models.AddGroupViewModel
#{
ViewBag.Title = "Add Groups";
}
<h2>Add Groups to subjects</h2>
#using (Html.BeginForm("AddGroup", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create new groups.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#{
List<SelectListItem> listItems1 = new List<SelectListItem>();
}
#foreach (var subject in Model)
{
listItems1.Add(new SelectListItem
{
Text = subject.name,
Value = subject.name,
Selected = true
});
}
#Html.LabelFor(m => m.subject_name, new {#class = "col-md-2 control-label"})
<div class="col-md-10">
#Html.DropDownListFor(m => m.subject_name, listItems1, new {#class = "form-control"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.qty, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.qty, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}
As you see, I am trying to use two models in my view. But gives an exception (well how to distinguish them). How do I combine those two models in a view?
Edit:
So I did what suggested in answer, but now I get such exception:
{"The class 'ClassDeclarationsThsesis.Models.Subject' has no parameterless constructor."}
The class looks like this:
namespace ClassDeclarationsThsesis.Models
{
using System;
using System.Collections.Generic;
public partial class Subject
{
private int v;
private int userid;
public Subject(int v, int userid, string name)
{
this.class_id = v;
this.user_id = userid;
this.name = name;
}
public int class_id { get; set; }
public int user_id { get; set; }
public string name { get; set; }
public virtual Group Group { get; set; }
public virtual Subjects_Users Subjects_Users { get; set; }
public virtual Task Task { get; set; }
}
}
How do I solve it?
Since you already have a view model, I'd use that:
#model ClassDeclarationsThsesis.Models.AddGroupViewModel
And simply add a property to that view model for the collection you also want to use:
public class AddGroupViewModel
{
[Required]
[Display(Name = "Subject")]
public string subject_name { get; set; }
[Required]
[Display(Name = "Number of Groups")]
public int qty { get; set; }
public List<Subject> Subjects { get; set; }
}
Then simply create an instance of that from your controller to send to the view:
var entities = new ClassDeclarationsDBEntities1();
var model = new AddGroupViewModel();
model.Subjects = entities.Subjects.ToList();
// set your other properties too?
return View(model);
Then in the view simply refer to the property on the Model instead of the model itself when you need that collection:
#foreach (var subject in Model.Subjects)
Basically, while you can use only one type for your model (since there's only one Model property available to the view in the framework), that type can be anything you like, even a custom view model type that you define.
I want to have a dropdown in my view, but that dropdown should have categories loaded from database.
I am using Entity Framework Code First Approach in MVC 5.
Here is my Model:
public class CreateProductModel
{
[Required]
public string Name { get; set; }
[Required]
public int CategoryID { get; set; }
public SelectList Categories { get; set; }
[MaxLength]
public double Price { get; set; }
public string Description { get; set; }
}
Controller:
public ActionResult Index()
{
var model = new ProductModel();
model.CreateProductModel.Categories = new SelectList(_db.Categories, "CategoryID", "Name", 1);
return View(model);
}
View:
<div class="form-group">
#Html.LabelFor(model => model.CreateProductModel.CategoryID, new { #class = "col-lg-2 control-label" })
<div class="col-lg-10">
#Html.DropDownListFor(model => model.CreateProductModel.CategoryID, new SelectList(Model.CreateProductModel.Categories, "CategoryID", "Name", 1), "Please Select Category");
</div>
</div>
I am getting this error:
Initialize CreateProductModel property:
var model = new ProductModel();
model.CreateProductModel = new CreateProductModel();
model.CreateProductModel.Categories = new SelectList(_db.Categories, "CategoryID", "Name", 1);
For a school assignment I need to make a poll with ASP.NET
The problem I get when trying to write the answers in the database is that only one question and one answer gets written into it.
This is the View
#model CinemaJamV2.WebUIV2.Models.EnqueteModel
#{
ViewBag.Title = "Enquete";
}
<h2>Enquete</h2>
#Html.ValidationSummary(true)
#using (Html.BeginForm("Enquete", "Enquete", new { vraag = "vraag", antwoord = "antwoord", naam = "naam", cijfer = "cijfer" }))
{
<div class="col-md-12">
#for(var i=0;i< Model.enquetevragen.Count();i++)
{
<div class="thumbnail">
#Html.LabelFor(model => model.enquetevragen[i].vraag, new { htmlAttributes = new { #class = "form-control" } })
#Html.EditorFor(model => model.enquete.antwoord, new { htmlAttributes = new { #class = "form-control" } })
#Html.EditorFor(model => model.enquete.cijfer, new { htmlAttributes = new { #class = "form-control" } })
</div>
}
</div>
<div class="col-md-12">
<p>Naam <input type="text" name="naam" /> </p>
<input type="submit" name="submit" value="Verzend" />
</div>
}
This is the Controller:
namespace CinemaJamV2.WebUIV2.Controllers
{
public class EnqueteController : Controller
{
private IRepository<Enquete> repository;
private IRepository<EnqueteVraag> a_repository;
private CineJamContext db = new CineJamContext();
public EnqueteController(IRepository<Enquete> a_model, IRepository<EnqueteVraag> vraag_model)
{
repository = a_model;
a_repository = vraag_model;
}
[HttpGet]
public ActionResult Enquete()
{
EnqueteModel enquetevragen = new EnqueteModel
{
enquetevragen = a_repository.List
};
return View(enquetevragen);
}
[HttpPost]
public ActionResult Enquete(Enquete enquete)
{
if (ModelState.IsValid)
{
db.Enquetes.Add(enquete);
db.SaveChanges();
return RedirectToAction("Enquete");
}
return View(enquete);
}
}
}
The ModelView:
namespace CinemaJamV2.WebUIV2.Models
{
public class EnqueteModel
{
public List<Enquete> enquetes {get; set;}
public Enquete enquete { get; set; }
public List<EnqueteVraag> enquetevragen { get; set; }
}
}
And this is the Model Enquete which should contain all the given answers:
namespace CinemaJamV2.Domain.Entities
{
[Table("Enquete")]
public partial class Enquete : IEntity
{
public int Id { get; set; }
[StringLength(1000)]
public string vraag { get; set; }
[StringLength(1000)]
//[Required]
public string antwoord { get; set; }
public int? cijfer {get; set;}
[StringLength(50)]
//[Required]
public string naam { get; set; }
}
}
This Model contains all the Questions
namespace CinemaJamV2.Domain.Entities
{
[Table("EnqueteVraag")]
public partial class EnqueteVraag : IEntity
{
public int Id { get; set; }
[StringLength(1000)]
public string vraag { get; set; }
}
}
The action for POST has only one instance of the Model as its parameter. You need to read this: Model binding to a list
YOu need to use view model that will have list of Enquete and then in post method again you need to do for loop and save it to database.
See following links for samples.
http://www.binaryintellect.net/articles/b1e0b153-47f4-4b29-8583-958aa22d9284.aspx
http://www.c-sharpcorner.com/UploadFile/pmfawas/Asp-Net-mvc-how-to-post-a-collection/
http://www.codeproject.com/Tips/855577/List-of-Model-Object-Post-to-Controller-in-ASP-NET
I'm working on a webapp for work, and I'm using standard CRUD style interactions. However, there are certain fields that I do not want the users updating, so I removed them from the view. However, if I don't explicitly set these fields, they're cleared when the model is updated in the database.
I'm concerned with what the proper method of populating the fields for my ViewModels is.
The rough idea I came up with was something like this:
My view model:
public class EditSoftwareTrackingViewModel
{
public EditSoftwareTrackingViewModel(SoftwareTracking model)
{
Id = model.Id;
SoftwareId = model.SoftwareId;
ComputerId = model.ComputerId;
SoftwareActionId = model.SoftwareActionId;
LastModified = model.LastModified;
Computer = model.Computer;
Software = model.Software;
SoftwareAction = model.SoftwareAction;
}
public int Id { get; set; }
[DisplayName("Software")]
public int SoftwareId { get; set; }
[DisplayName("Computer")]
public int ComputerId { get; set; }
[DisplayName("Software Action")]
public int SoftwareActionId { get; set; }
[DisplayName("Last Modified")]
public DateTime? LastModified { get; set; }
public virtual Computer Computer { get; set; }
public virtual Software Software { get; set; }
public virtual SoftwareAction SoftwareAction { get; set; }
}
My main model
[Table("asset.SoftwareTracking")]
public partial class SoftwareTracking
{
public int Id { get; set; }
[DisplayName("Software")]
public int SoftwareId { get; set; }
[DisplayName("Computer")]
public int ComputerId { get; set; }
[DisplayName("Date Entered")]
public DateTime? EnteredDate { get; set; }
[DisplayName("Software Action")]
public int SoftwareActionId { get; set; }
[DisplayName("Last Modified")]
public DateTime? LastModified { get; set; }
public virtual Computer Computer { get; set; }
public virtual Software Software { get; set; }
public virtual SoftwareAction SoftwareAction { get; set; }
}
And my controller using the view model
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
EditSoftwareTrackingViewModel softwaretracking = new EditSoftwareTrackingViewModel(db.SoftwareTrackings.Find(id));
if (softwaretracking == null)
{
return HttpNotFound();
}
GeneratePageData(softwaretracking.Software.Id);
return View(softwaretracking);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(EditSoftwareTrackingViewModel softwaretracking)
{
if (ModelState.IsValid)
{
softwaretracking.LastModified = DateTime.Now;
var softwareTrack = db.SoftwareTrackings.Find(softwaretracking.Id);
softwareTrack = new SoftwareTracking
{
Computer = softwaretracking.Computer,
ComputerId = softwaretracking.ComputerId,
LastModified = softwaretracking.LastModified,
Software = softwaretracking.Software,
SoftwareAction = softwaretracking.SoftwareAction,
SoftwareActionId = softwaretracking.SoftwareActionId,
SoftwareId = softwaretracking.SoftwareId,
EnteredDate = softwareTrack.EnteredDate
};
db.Entry(softwareTrack).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
GeneratePageData(softwaretracking.Software.Id);
return View(softwaretracking);
}
Is there a better alternative? Or should I continue to create my view models in this manner?
EDIT
My business logic and view
private void GeneratePageData(int? id = null)
{
ViewBag.Computers = new SelectList(db.Computers, "Id", "ComputerName");
ViewBag.SoftwareActions = new SelectList(db.SoftwareActions, "Id", "ActionPerformed");
var usedSoft = (from softTrack in db.SoftwareTrackings
where (softTrack.SoftwareActionId != 3)
select softTrack.Software);
var softwareList = (from soft in db.Softwares
where (
((from softTrack in db.SoftwareTrackings
where (softTrack.SoftwareActionId != 3 && softTrack.SoftwareId == soft.Id)
select softTrack.Software).Count() < soft.KeyQuantity)
&& !(soft.AssetStatusId == 4 || soft.AssetStatusId == 5)
|| soft.Id == id)
select soft).ToList();
ViewBag.SoftwareList = softwareList.Select(t => new SelectListItem
{
Text = t.SoftwareIdNameFull,
Value = t.Id.ToString()
});
}
And my view
#model Lighthouse_Asset_Manager.Models.EditSoftwareTrackingViewModel
#{
ViewBag.Title = "Edit Software Install";
Layout = "";
}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
×
</button>
<h4 class="modal-title" id="myModalLabel">Edit Software Install</h4>
</div>
<div class="modal-body">
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "computerForm" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.Id)
<div class="form-horizontal">
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.SoftwareId, "Software", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("SoftwareId", (IEnumerable<SelectListItem>)ViewBag.SoftwareList, "-- Select --", new
{
#style = "width:100%",
#class = "select2"
})
#Html.ValidationMessageFor(model => model.SoftwareId)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ComputerId, "Computer", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("ComputerId", (IEnumerable<SelectListItem>)ViewBag.Computers, "-- Select --", new
{
#style = "width:100%",
#class = "select2"
})
#Html.ValidationMessageFor(model => model.ComputerId)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SoftwareActionId, "Action", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("SoftwareActionId", (IEnumerable<SelectListItem>)ViewBag.SoftwareActions, "-- Select --", new
{
#style = "width:100%",
#class = "form-control"
})
#Html.ValidationMessageFor(model => model.SoftwareActionId)
</div>
</div>
<div class="form-actions no-color">
<button type="submit" class="btn btn-primary btn-sm"><i class="fa fa-floppy-o"></i> Edit Install Record</button>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
</div>
}
</div>
You approach of using a view model is a good one. The answers to this question explains some of the benefits including preventing over-posting attacks, using view specific display and validation attributes and including view specific properties such as SelectLists. Tools such as automapper can make it easy to map between you data and view models and reduce the code in the controller. A few changes I would suggest to your view model. The LastModified, Computer, Software and SoftwareAction properties are not required (you not binding to these), and I would include the SelectList properties in the model rather than ViewBag
View model
public class EditSoftwareTrackingViewModel
{
public int Id { get; set; }
[Display(Name="Software")]
public int SoftwareId { get; set; }
[Display(Name="Computer")]
public int ComputerId { get; set; }
[Display(Name="Software Action")]
public int SoftwareActionId { get; set; }
public SelectList Computers { get; set; }
public SelectList SoftwareActions{ get; set; }
public SelectList SoftwareList{ get; set; }
}
Then change the GeneratePageData() method to accept the view model
private void GeneratePageData(EditSoftwareTrackingViewModel model)
{
model.Computers = new SelectList(db.Computers, "Id", "ComputerName");
....
and in the view (always preferable to use the strongly typed helpers)
#Html.DropDownListFor(m => m.SoftwareId, Model.SoftwareList, "-- Select --", new { #class = "select2" })
A few other things to note.
You should use the [Display(Name="..")] attribute (not
[DisplayName(..)])
When you set the LastModified property, you should consider using
UCT time.
The hidden input for the Id property is not required in the view
(assuming your using the default {controller}/{action}/{id} route
mapping) - its added to the route values and will be bound anyway
Unless you specifically want an id attribute for the form, you can
just use #using(Html.BeginForm()) {
You do not need the second parameter in LabelFor() - it can be just
Html.LabelFor(m => m.SoftwareId, new { #class = "control-label
col-md-2" }) since you have specified it in the [Display]
attribute
Finally, if you want to simplify your view further, you could consider custom EditorTemplates or html helpers as indicated in this answer which would allow you to replace
<div class="form-group">
#Html.LabelFor(model => model.SoftwareId, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.SoftwareId, Model.SoftwareList, "-- Select --", new { #class = "select2" })
#Html.ValidationMessageFor(model => model.SoftwareId)
</div>
</div>
with (custom EditorTemplate)
#Html.EditorFor(m => m.SoftwareId, "BootstrapSelect", Model.SoftwareList)
or (custom HtmlHelper)
#Html.BootstrapDropDownFor(m => m.SoftwareId, Model.SoftwareList)
You should use the AutoMapper to make the mapping between Model and ViewModel cleaner. Use this code to create the mapper first.
Mapper.CreateMap<SoftwareTracking, EditSoftwareTrackingViewModel>();
Mapper.CreateMap<EditSoftwareTrackingViewModel, SoftwareTracking>();
When you want to create a viewmodel from model, do this:
public ActionResult Edit(int? id)
{
SoftwareTracking tracking = db.SoftwareTrackings.Find(id);
EditSoftwareTrackingViewModel viewmodel =
Mapper.Map<SoftwareTracking, EditSoftwareTrackingViewModel>(tracking);
return View(viewmodel);
}
When you want to populate the info from the viewmodel back to the model, do this
public ActionResult Edit(EditSoftwareTrackingViewModel vm)
{
if (ModelState.IsValid)
{
vm.LastModified = DateTime.Now;
var softwareTrack = db.SoftwareTrackings.Find(softwaretracking.Id);
softwareTrack =
Mapper.Map<EditSoftwareTrackingViewModel, SoftwareTracking>(vm, softwareTrack);
db.Entry(softwareTrack).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
To patch update your model without loading the object from Db. Try Attach:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(EditSoftwareTrackingViewModel softwaretracking)
{
if (ModelState.IsValid)
{
var softwareTrack = new SoftwareTracking
{
Computer = softwaretracking.Computer,
ComputerId = softwaretracking.ComputerId,
LastModified = softwaretracking.LastModified,
Software = softwaretracking.Software,
SoftwareAction = softwaretracking.SoftwareAction,
SoftwareActionId = softwaretracking.SoftwareActionId,
SoftwareId = softwaretracking.SoftwareId,
EnteredDate = softwareTrack.EnteredDate
};
db.SoftwareTrackings.Attach(softwareTrack);
db.Entry(softwareTrack).Property(a => a.Computer).IsModified = true;
db.Entry(softwareTrack).Property(a => a.ComputerId).IsModified = true;
db.Entry(softwareTrack).Property(a => a.LastModified).IsModified = true;
db.Entry(softwareTrack).Property(a => a.Computer).IsModified = true;
db.Entry(softwareTrack).Property(a => a.Software).IsModified = true;
db.Entry(softwareTrack).Property(a => a.SoftwareAction).IsModified = true;
db.Entry(softwareTrack).Property(a => a.SoftwareActionId).IsModified = true;
db.Entry(softwareTrack).Property(a => a.SoftwareId).IsModified = true;
db.SaveChanges();
return RedirectToAction("Index");
}
GeneratePageData(softwaretracking.Software.Id);
return View(softwaretracking);
}
Regarding the second question about whether to use ViewModel or just use the Model directly. This is really a matter of opinion, each approach has its pros and cons. I don't have strong opinion about this, i just want to point out these pros and cons for your consideration:
Using the model directly saves us from creating the viewModel, resulting in smaller source code and avoiding mapping logic but it would mix concerns. Because you use the same Model for your domain logic and for communcating with the client, any changes to the model may propagate up to the client if we don't take that into account.
Using the viewModel is a good way for separation of concerns but it would require more effort and mapping logic (maybe slow down the performance a bit). To apply ViewModel efficiently, I suggest using a mapper: https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
This is the Model Class
[Table("CURRENCY")]
public class CurrencyClass : ICurrency
{
private Int32 mCURRENCY_ID = default(Int32);
[Key]
public virtual Int32 CURRENCY_ID
{
get { return mCURRENCY_ID; }
set { mCURRENCY_ID = value; }
}
private string mCURRENCY_NAME = default(string);
public virtual string CURRENCY_NAME
{
get { return mCURRENCY_NAME;}
set { mCURRENCY_NAME = value;}
}
private string mCURRENCY_DESC = default(string);
public virtual string CURRENCY_DESC
{
get { return mCURRENCY_DESC; }
set { mCURRENCY_DESC = value; }
}
private string mCURRENCY_SYMBOLE = default(string);
public virtual string CURRENCY_SYMBOLE
{
get { return mCURRENCY_SYMBOLE; }
set { mCURRENCY_SYMBOLE = value; }
}
private Int32 mcreated_by = default(Int32);
public virtual Int32 created_by
{
get { return mcreated_by; }
set { mcreated_by = value; }
}
private DateTime mcreated_date = default(DateTime);
public virtual DateTime created_date
{
get { return mcreated_date; }
set { mcreated_date = value; }
}
private Int32 mmodified_by = default(Int32);
public virtual Int32 modified_by
{
get { return mmodified_by; }
set { mmodified_by = value; }
}
private DateTime mmodified_date = default(DateTime);
public virtual DateTime modified_date
{
get { return mmodified_date; }
set { mmodified_date = value; }
}
}
This is the ViewModel
public class CurrencyViewModel
{
[Key]
public Int32 CURRENCY_Id { get; set; }
[Required(ErrorMessage="Currency Name is required")]
public string CURRENCY_NAME { get; set; }
[Required(ErrorMessage="Currency Description is required")]
public string CURRENCY_DESC { get; set; }
[Required(ErrorMessage = "Currency Symbole is Required")]
public string CURRENCY_SYMBOLE { get; set; }
}
This is the Action
[HttpPost]
[ActionName("Create")]
public ActionResult Create(CurrencyViewModel vm)
{
if (!ModelState.IsValid)
{
return View("Create");
}
obj.CURRENCY_NAME = vm.CURRENCY_NAME;
obj.CURRENCY_DESC = vm.CURRENCY_DESC;
obj.CURRENCY_SYMBOLE = vm.CURRENCY_SYMBOLE;
obj.created_by = 1;
obj.created_date = DateTime.Now;
obj.modified_by = 1;
obj.modified_date = DateTime.Now;
db.Currencies.Add(obj);
db.SaveChanges();
return RedirectToAction("Index");
}
I try to add new entity in database in controller action.
This is my model class
public class Product
{
public int ProductID { get; set; }
[Required(ErrorMessage = "Please enter product name")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter product model")]
public string Model { get; set; }
[Required(ErrorMessage = "Please enter product serial")]
public string Serial { get; set; }
[Required(ErrorMessage = "Please choose dealer")]
public int DealerID { get; set; }
[Required]
public Guid ClientID { get; set; }
[Required(ErrorMessage = "Please choose employee")]
public Guid EmployeeID { get; set; }
public virtual Dealer Dealer { get; set; }
public virtual Client Client { get; set; }
public virtual Employee Employee { get; set; }
[DisplayName("Commercial use")]
public bool UseType { get; set; }
}
This is actions for creating new product in database
public ViewResult Create()
{
PopulateDropDownLists();
var model = new Product();
return View(model);
}
[HttpPost]
public ActionResult Create(Product model)
{
try
{
if (ModelState.IsValid)
{
_repo.GetRepository<Product>().Add(model);
_repo.Save();
TempData["message"] = "Product was successfully created";
return RedirectToAction("List");
}
}
catch (DataException)
{
TempData["error"] =
"Unable to save changes. Try again, and if the problem persists, see your system administrator.";
return View("Error");
}
PopulateDropDownLists();
return View("Create");
}
CreateView has appropriate model type (Product type in this case). Code below
#using System.Web.Mvc.Html
#model STIHL.WebUI.Models.Product
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.Name)
#Html.EditorFor(m => m.Model)
#Html.EditorFor(m => m.Serial)
<div class="form-group">
#Html.LabelFor(m => m.DealerID, "Dealer")
#Html.DropDownListFor(m => m.DealerID, new SelectList((IEnumerable)TempData["Dealers"],"DealerID", "DealerNumber"), string.Empty, new {#class = "form-control"})
#Html.ValidationMessageFor(m => m.DealerID, null, new {#class = "help-block"})
</div>
<div class="form-group">
#Html.LabelFor(m => m.EmployeeID, "Employee",new {#class = "control-label"})
#Html.DropDownListFor(m => m.EmployeeID, new SelectList((IEnumerable)TempData["Employees"],"EmployeeID", "FullName"),string.Empty, new {#class="form-control"})
#Html.ValidationMessageFor(m => m.EmployeeID, null, new {#class = "help-block"})
</div>
<div class ="ok-cancel-group">
<input class="btn btn-primary" type="submit" value="Create" />
#Html.ActionLink("Cancel", "List","Product",new {#class = "btn btn-primary"})
</div>
}
i always get null reference instead model in [HttpPost] action, but if i use ViewModel instead Model everything is ok (ViewModel code below)
public class ProductViewModel
{
public Product Product { get; set; }
}
I think it cause model class has virtual properties, but anyway i don't understand why it's ok when i use ViewModel.
Can anyone answer me?
Thx in advance.
The virtual properties won't change the outcome. The issue is that the view is written to bind to the view model, therefore accepting the model isn't going to work. If you want to use the model; then bind the view to the model.