Drop down list binding from another model in MVC - asp.net-mvc

I am new to asp.net mvc
I have two tables tblEmployee and tblDepartment in both the tables common field is department id.
If the user creating new employee they have to select their department list from tblDepartment table.I am getting list of departments from that table there is no issue in that,but when i submitting the form departmentid is going null into the DB.
Models
public partial class Department
{
public Department()
{
this.tblEmployees = new HashSet<Employee>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> tblEmployees { get; set; }
public Employee employee { get; set; }
}
public partial class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
public Nullable<int> DepartmentId { get; set; }
public virtual Department tblDepartment { get; set; }
public List<Department> deprtment { get; set; }
public virtual string Department { get; set; }
public bool available { get; set; }
}
Controller:
public ActionResult Create()
{
SampleDbContext Db = new SampleDbContext();
List<Employee> employees = Db.Employees.Include("tblDepartment").ToList();
ViewBag.list = new SelectList(Db.Departments, "Id", "Name");
return View();
}
[HttpPost]
public ActionResult Create( Employee employee)
{
SampleDbContext Db = new SampleDbContext();
if (ModelState.IsValid)
{
Db.Employees.Add(employee);
Db.SaveChanges();
return RedirectToAction("Index");
}
return View(employee);
}
View:
#model EmployeeList.Models.Employee
....
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Employee</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
.... // controls for other properties of Employee
<div class="form-group">
#Html.LabelFor(model => model.DepartmentId, "DepartmentId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("list","select Depar")
#Html.ValidationMessageFor(model => model.DepartmentId, "", 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>
}

Related

how i can send multivalue to create action

i have a doctor i want add doctor subspecialty to the doctor from sub specialties table many to many relationship
i need to add subspecialties from multiselect list but my controller only add first selection , i want my create controller take all passed subspecialties and create it
my model
public partial class DoctorSubSpecialty
{
public int Id { get; set; }
public Nullable<int> DoctorId { get; set; }
public Nullable<int> SubSpecialtyId { get; set; }
public virtual DoctorProfile DoctorProfile { get; set; }
public virtual SubSpecialty SubSpecialty { get; set; }
}
}
create get action
public ActionResult Create()
{
ViewBag.DoctorId = new SelectList(db.DoctorProfiles, "Id", "FullName");
ViewBag.SubSpecialtyId = new MultiSelectList(db.SubSpecialties, "id", "Name");
return View();
}
create post action
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "Id,DoctorId,SubSpecialtyId")] DoctorSubSpecialty doctorSubSpecialty)
{
DoctorSubSpecialty doctorSub = db.DoctorSubSpecialties.Where(d => d.DoctorId == doctorSubSpecialty.DoctorId & d.SubSpecialtyId == doctorSubSpecialty.SubSpecialtyId).FirstOrDefault();
if (doctorSub == null) {
db.DoctorSubSpecialties.Add(doctorSubSpecialty);
await db.SaveChangesAsync();
}
my view
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>DoctorSubSpecialty</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.DoctorId, "DoctorId", htmlAttributes: new { #class = "control-label col-md-2", #id = "DoctorID" })
<div class="col-md-10">
#Html.DropDownList("DoctorId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.DoctorId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SubSpecialtyId, "SubSpecialtyId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("SubSpecialtyId",(MultiSelectList)ViewBag.SubSpecialtyId, htmlAttributes: new { #multiple = "multiple", #class = "form-control" })
#Html.ValidationMessageFor(model => model.SubSpecialtyId, "", 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>
}
Create a ViewModel specific to your usecase that can actually transport more than one Id.
I.e. you will need an int[] to bind the selection to.
A ViewModel also helps you to get rid of all this ViewBag and [Bind] nonsense.
public class CreateDoctorSubSpecialtyViewModel {
// These are the selected values to be posted back
public int DoctorId { get; set; }
public int[] SubSpecialtyIds { get; set; }
// These are the possible values for the dropdowns
public IEnumerable<SelectListItem> DoctorProfiles { get; set; }
public IEnumerable<SelectListItem> SubSpecialties { get; set; }
}
GET action - initialize the ViewModel and pass it to the View:
[HttpGet]
public ActionResult Create() {
var doctorProfiles = db.DoctorProfiles.Select(d =>
new SelectListItem {
Text = d.FullName,
Value = d.Id
}
).ToArray();
var subSpecialties = db.SubSpecialties.Select(s =>
new SelectListItem {
Text = s.Name,
Value = s.id
}
).ToArray();
var viewModel = new CreateDoctorSubSpecialtyViewModel {
DoctorProfiles = doctorProfiles,
SubSpecialties = subSpecialties
};
return View("Create", viewModel);
}
View "Create.cshtml" (styling removed for clarity) - tell MVC which ViewModel we want to use with #model:
#model CreateDoctorSubSpecialtyViewModel
#using (Html.BeginForm("Create", "YourControllerName", FormMethod.Post)) {
#Html.DropDownListFor(m => m.DoctorId, Model.DoctorProfiles)
#Html.DropDownListFor(m => m.SubSpecialtyIds, Model.SubSpecialties, new { multiple = "multiple" })
<input type="submit" />
}
POST action - use Linq Contains to test against multiple submitted SubSpecialtyIds:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(CreateDoctorSubSpecialtyViewModel postData) {
DoctorSubSpecialty[] allSelectedSubSpecialities = db.DoctorSubSpecialties
.Where(d => d.DoctorId == postData.DoctorId
&& postData.SubSpecialtyIds.Contains(d.SubSpecialtyId))
.ToArray();
// ...
}
EDIT #Html.DropDownListFor requires an IEnumerable<SelectListItem> as second parameter.

ID identity field value does not increase

I have a form to bind id field as hidden value. But in controller, the id (key, auto identity increment) field always 0. Below is my code:
Model.cs
public partial class A
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
[StringLength(255)]
[Display(Name = "Institution Name")]
[Required]
public string InstitutionName { get; set; }
[Display(Name = "Public")]
[DefaultValue(false)]
public bool Category1 { get; set; }
[Display(Name = "Private")]
[DefaultValue(false)]
[Display(Name = "Online")]
[DefaultValue(false)]
public bool Category3 { get; set; }
[
[Display(Name = "Active?")]
[DefaultValue(false)]
public bool active { get; set; }
public A()
{
Category1 = false;
Category2 = false;
Category3 = false;
active = true;
}
}
Controller:
...
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "id,InstitutionName,Category1,Category2,Category3,active")] A A)
{
if (ModelState.IsValid)
{
db.A.Add(A);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(A);
}
}
...
View - Create.cshtml:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>TransferSearch_revised</h4>
<hr />
#Html.HiddenFor(model=> model.id)
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.InstitutionName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.InstitutionName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.InstitutionName, "", new { #class = "text-danger" })
</div>
</div>
...
The id value either 0 or empty. What's wrong with my code? Thanks.

Button repeatedly calls GET method and does not POST when editing

I am trying to edit an entry in my database, but when I click submit, it just keeps calling the GET method over and over again and I cannot figure out why. I have tested this through breakpoints and there is no evidence of the POST method running - is it something to do with my Manufacturer binding?
Controller
// GET: Model/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Model model = db.Models.Find(id);
if (model == null)
{
return HttpNotFound();
}
ViewBag.Manufacturers = GetManufacturerList(model);
return View(model);
}
// POST: Model/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var modelToUpdate = db.Models.Find(id);
if (TryUpdateModel(modelToUpdate, "",
new string[] { "ModelName", "ManufacturerID" }))
{
try
{
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
ViewBag.Manufacturers = GetManufacturerList();
return View(modelToUpdate);
}
View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Model</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.ModelID)
<div class="form-group">
#Html.LabelFor(model => model.ModelName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ModelName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ModelName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Manufacturer.ManufacturerName, "Manufacturer",
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.DropDownList("ManufacturerID", (List<SelectListItem>)ViewBag.Manufacturers,
htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Manufacturer.ManufacturerName, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
Models:
public class Model
{
[Required]
[Display(Name = "Manufacturer")]
[ForeignKey("Manufacturer")]
public int ManufacturerID { get; set; }
[Required]
public int ModelID { get; set; }
[Required]
[StringLength(50, ErrorMessage = "Model cannot be longer than 50 characters.")]
[RegularExpression(#"^[a-zA-Z0-9.-/() ]+$", ErrorMessage = "Invalid characters used. A-Z or a-z, 0-9, '.', '-', '()' and '/' allowed.")]
[Display(Name = "Model")]
public string ModelName { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
public class Manufacturer
{
[Required]
public int ManufacturerID { get; set; }
[Required]
[StringLength(50, ErrorMessage = "Manufacturer cannot be longer than 50 characters.")]
[RegularExpression(#"^[a-zA-Z0-9.-/() ]+$", ErrorMessage = "Invalid characters used. A-Z or a-z, 0-9, '.', '-', '()' and '/' allowed.")]
[Display(Name = "Manufacturer")]
public string ManufacturerName { get; set; }
public virtual ICollection<Model> Models { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
Thanks in advance. Any help is greatly appreciated.
Your HttpPost method is named "EditPost". Shouldn't it be named simply "Edit" like this?
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Model model)
{
Here is a tutorial that might help you: https://www.asp.net/mvc/overview/older-versions/getting-started-with-aspnet-mvc4/examining-the-edit-methods-and-edit-view
Figured it out - I forgot to add the ActionName attribute as below:
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{...}

Get two tables data on a single MVC View

I am not so much experienced with MVC in ASP.NET. Currently working on Visual Studio 2015 Community on a demo MVC project.
I am having difficulties having two tables combined in a view.
Following are two tables of concern from few tables.
I want to show data from both the tables at the same time in a single View(HTML Page).
TABLE - COMPLAIN
CREATE TABLE [dbo].[COMPLAIN](
[JOBSHEET_NO] [int] IDENTITY(1,1) NOT NULL,
[COMPANY_NAME] [nvarchar](50) NULL,
[MODEL_NAME] [nvarchar](50) NULL,
[IMEI_SRNO] [nvarchar](50) NULL,
[BATTERY_WITH_MOBILE] [nvarchar](50) NULL,
[MEMORYCARD_WITH_MOBILE] [nvarchar](50) NULL,
[FAULT_ID] [int] NOT NULL,
[CUSTOMER_NAME] [nvarchar](50) NULL,
[CUSTOMER_MOBILE] [nvarchar](50) NULL,
[ASSIGNED_TO_TECHNICIAN] [nvarchar](50) NULL,
[REMARKS] [nvarchar](500) NULL,
[CREATE_TIMESTAMP] [datetime] NULL,
[LAST_EDIT_TIMESTAMP] [datetime] NULL,
[IN_TIMESTAMP] [datetime] NULL,
[USER_ID] [nvarchar](50) NULL,
[ESTIMATE_AMOUNT] [float] NULL,
[ESTIMATE_AMOUNT_OK_FROM_CUSTOMER] [nvarchar](50) NULL,
[OUT_TIMESTAMP] [datetime] NULL,
[JOBSHEET_COMPLETE_STATUS] [nvarchar](50) NULL,
[NARRATION] [nvarchar](500) NULL,
CONSTRAINT [PK_COMPLAIN] PRIMARY KEY CLUSTERED
(
[JOBSHEET_NO] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
TABLE - REPAIRING
CREATE TABLE [dbo].[REPAIRING](
[JOBSHEET_NO] [int] NOT NULL,
[IN_TIMESTAMP] [datetime] NULL,
[CREATE_TIMESTAMP] [datetime] NULL,
[LAST_EDIT_TIMESTAMP] [datetime] NULL,
[ESTIMATE_AMOUNT] [float] NULL,
[ESTIMATE_AMOUNT_OK_FROM_CUSTOMER] [nvarchar](50) NULL,
[START_REPAIRING_TIMESTAMP] [datetime] NULL,
[END_REPAIRING_TIMESTAMP] [datetime] NULL,
[OUT_TIMESTAMP] [datetime] NULL,
[USER_ID] [nvarchar](50) NULL,
[NARRATION] [nvarchar](500) NULL,
CONSTRAINT [PK_REPAIRING] PRIMARY KEY CLUSTERED
(
[JOBSHEET_NO] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[REPAIRING] WITH CHECK ADD CONSTRAINT [FK_REPAIRING_COMPLAIN] FOREIGN KEY([JOBSHEET_NO])
REFERENCES [dbo].[COMPLAIN] ([JOBSHEET_NO])
GO
ALTER TABLE [dbo].[REPAIRING] CHECK CONSTRAINT [FK_REPAIRING_COMPLAIN]
GO
I am having FK relationship between those two tables.
I would also like to know if data from both the tables can be available without any FK relationship.
Following are my models.
COMPLAIN.cs
namespace WebMSM.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public partial class COMPLAIN
{
[Key]
[ReadOnly(true)]
[Required]
[DisplayName("JOBSHEET NO")]
public int JOBSHEET_NO { get; set; }
[Required]
[DisplayName("COMPANY NAME")]
public string COMPANY_NAME { get; set; }
[Required]
[DisplayName("MODEL NAME")]
public string MODEL_NAME { get; set; }
[Required]
[DisplayName("IMEI")]
public string IMEI_SRNO { get; set; }
[Required]
[DisplayName("BATTERY WITH MOBILE")]
public string BATTERY_WITH_MOBILE { get; set; }
[Required]
[DisplayName("MEMORY CARD WITH MOBILE")]
public string MEMORYCARD_WITH_MOBILE { get; set; }
[Required]
[DisplayName("FAULT")]
public int FAULT_ID { get; set; }
[Required]
[DisplayName("CUSTOMER NAME")]
public string CUSTOMER_NAME { get; set; }
[Required]
[DisplayName("CUSTOMER MOBILE")]
public string CUSTOMER_MOBILE { get; set; }
[Required]
[DisplayName("TECHNICIAN")]
public string ASSIGNED_TO_TECHNICIAN { get; set; }
[DisplayName("REMARKS")]
public string REMARKS { get; set; }
public Nullable<System.DateTime> CREATE_TIMESTAMP { get; set; }
public Nullable<System.DateTime> LAST_EDIT_TIMESTAMP { get; set; }
public Nullable<System.DateTime> IN_TIMESTAMP { get; set; }
[Required]
[DisplayName("USER ID")]
public string USER_ID { get; set; }
[DisplayName("ESTIMATE AMOUNT")]
public Nullable<double> ESTIMATE_AMOUNT { get; set; }
[DisplayName("ESTIMATE AMOUNT OK?")]
public string ESTIMATE_AMOUNT_OK_FROM_CUSTOMER { get; set; }
public Nullable<System.DateTime> OUT_TIMESTAMP { get; set; }
[DisplayName("STATUS")]
public string JOBSHEET_COMPLETE_STATUS { get; set; }
[Required]
[DisplayName("NARRATION")]
public string NARRATION { get; set; }
public virtual MASTER_FAULT MASTER_FAULT { get; set; }
public virtual REPAIRING REPAIRING { get; set; }
}
}
REPAIRING.cs
namespace WebMSM.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public partial class REPAIRING
{
[Required]
[DisplayName("JOBSHEET NO")]
public int JOBSHEET_NO { get; set; }
public Nullable<System.DateTime> IN_TIMESTAMP { get; set; }
public Nullable<System.DateTime> CREATE_TIMESTAMP { get; set; }
public Nullable<System.DateTime> LAST_EDIT_TIMESTAMP { get; set; }
[Required]
[DisplayName("ESTIMATE AMOUNT")]
public Nullable<double> ESTIMATE_AMOUNT { get; set; }
[Required]
[DisplayName("ESTIMATE AMOUNT OK?")]
public string ESTIMATE_AMOUNT_OK_FROM_CUSTOMER { get; set; }
[DisplayName("START REPAIR TIME")]
public Nullable<System.DateTime> START_REPAIRING_TIMESTAMP { get; set; }
[DisplayName("END REPAIR TIME")]
public Nullable<System.DateTime> END_REPAIRING_TIMESTAMP { get; set; }
[DisplayName("OUT TIME")]
public Nullable<System.DateTime> OUT_TIMESTAMP { get; set; }
public string USER_ID { get; set; }
[DisplayName("NARRATION")]
public string NARRATION { get; set; }
public virtual COMPLAIN COMPLAIN { get; set; }
}
}
Now I have created a RepairingController which displays list of COMPLAINs on its index View.
From that View, by Clicking 'Edit' link, I would like to go to Edit view in which data from both the tables about that record should be available.
Following is RepairingController.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using WebMSM.Models;
namespace WebMSM.Controllers
{
public class RepairingController : Controller
{
private MSMContext db = new MSMContext();
// GET: Repairing
public ActionResult Index()
{
return View(db.COMPLAINs.ToList());
}
// GET: Repairing/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
REPAIRING rEPAIRING = db.REPAIRINGs.Find(id);
if (rEPAIRING == null)
{
return HttpNotFound();
}
return View(rEPAIRING);
}
// GET: Repairing/Create
public ActionResult Create()
{
return View();
}
// POST: Repairing/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "JOBSHEET_NO,IN_TIMESTAMP,CREATE_TIMESTAMP,LAST_EDIT_TIMESTAMP,ESTIMATE_AMOUNT,ESTIMATE_AMOUNT_OK_FROM_CUSTOMER,START_REPAIRING_TIMESTAMP,END_REPAIRING_TIMESTAMP,OUT_TIMESTAMP,USER_ID,NARRATION")] REPAIRING rEPAIRING)
{
if (ModelState.IsValid)
{
db.REPAIRINGs.Add(rEPAIRING);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(rEPAIRING);
}
// GET: Repairing/Edit/5
public ActionResult Edit(int? id)
{
var lstOKNOTOK = new List<SelectListItem>()
{
new SelectListItem {Text="OK",Value="OK" },
new SelectListItem {Text="NOT_OK",Value="NOT_OK" },
};
ViewBag.ESTIMATE_AMOUNT_OK_FROM_CUSTOMER = lstOKNOTOK;
REPAIRING rEPAIRING = db.REPAIRINGs.Find(id);
if (rEPAIRING == null)
{
return HttpNotFound();
}
return View(rEPAIRING);
}
// POST: Repairing/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "JOBSHEET_NO,IN_TIMESTAMP,CREATE_TIMESTAMP,LAST_EDIT_TIMESTAMP,ESTIMATE_AMOUNT,ESTIMATE_AMOUNT_OK_FROM_CUSTOMER,START_REPAIRING_TIMESTAMP,END_REPAIRING_TIMESTAMP,OUT_TIMESTAMP,USER_ID,NARRATION")] REPAIRING rEPAIRING)
{
if (ModelState.IsValid)
{
db.Entry(rEPAIRING).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(rEPAIRING);
}
// GET: Repairing/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
REPAIRING rEPAIRING = db.REPAIRINGs.Find(id);
if (rEPAIRING == null)
{
return HttpNotFound();
}
return View(rEPAIRING);
}
// POST: Repairing/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
REPAIRING rEPAIRING = db.REPAIRINGs.Find(id);
db.REPAIRINGs.Remove(rEPAIRING);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
Following is Edit.cshtml View For RepairingController.cs
#model WebMSM.Models.REPAIRING
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>REPAIRING</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.JOBSHEET_NO)
<div class="form-group">
#Html.LabelFor(model => model.JOBSHEET_NO, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.TextBoxFor(model => model.JOBSHEET_NO, new { #class = "form-control" ,#readonly="readonly"} )
#Html.ValidationMessageFor(model => model.JOBSHEET_NO, "", new { #class = "text-danger" })
</div>
</div>
#*<div class="form-group">
#Html.LabelFor(model => model.IN_TIMESTAMP, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.EditorFor(model => model.IN_TIMESTAMP, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.IN_TIMESTAMP, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CREATE_TIMESTAMP, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.EditorFor(model => model.CREATE_TIMESTAMP, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CREATE_TIMESTAMP, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.LAST_EDIT_TIMESTAMP, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.EditorFor(model => model.LAST_EDIT_TIMESTAMP, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LAST_EDIT_TIMESTAMP, "", new { #class = "text-danger" })
</div>
</div>*#
<div class="form-group">
#Html.LabelFor(model => model.ESTIMATE_AMOUNT, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.EditorFor(model => model.ESTIMATE_AMOUNT, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ESTIMATE_AMOUNT, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ESTIMATE_AMOUNT_OK_FROM_CUSTOMER, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.DropDownListFor(model => model.ESTIMATE_AMOUNT_OK_FROM_CUSTOMER,ViewBag.ESTIMATE_AMOUNT_OK_FROM_CUSTOMER as SelectList, new { #class = "form-control" } )
#Html.ValidationMessageFor(model => model.ESTIMATE_AMOUNT_OK_FROM_CUSTOMER, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.START_REPAIRING_TIMESTAMP, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.EditorFor(model => model.START_REPAIRING_TIMESTAMP, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.START_REPAIRING_TIMESTAMP, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.END_REPAIRING_TIMESTAMP, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.EditorFor(model => model.END_REPAIRING_TIMESTAMP, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.END_REPAIRING_TIMESTAMP, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.OUT_TIMESTAMP, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.EditorFor(model => model.OUT_TIMESTAMP, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.OUT_TIMESTAMP, "", new { #class = "text-danger" })
</div>
</div>
#*<div class="form-group">
#Html.LabelFor(model => model.USER_ID, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.EditorFor(model => model.USER_ID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.USER_ID, "", new { #class = "text-danger" })
</div>
</div>*#
<div class="form-group">
#Html.LabelFor(model => model.NARRATION, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-6">
#Html.EditorFor(model => model.NARRATION, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.NARRATION, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-5 col-md-6">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Thanks in advance.
You should create a new view model class which has properties to represent data from both the tables
public class ComplaintDetailsVm
{
public Int JobSheetNo {set;get;}
public string CompanyName {set;get;}
public string CustomerName {set;get;}
public Decimal EsitmatedAmount {set;get;}
//Add other properties AS NEEDED
}
And use that for your view.
public ActionResult Edit(int id)
{
var vm = new ComplaintDetailsVm();
var r =db.REPAIRINGs.Find(id);
if(r!=null)
{
vm.JobSheetNo = r.JOBSHEET_NO;
vm.CustomerName= r.CUSTOMER_NAME;
//Map other properties here as needed
if(r.REPAIRING !=null)
{
vm.EstimatedAmount = r.ESTIMATED_AMOUNT;
//Map other properties here as needed
}
}
return View(vm);
}
And your view
#model ComplantDetailsVm
#using(Html.BeginForm())
{
#Html.TextBoxFor(s=>s.CompanyName)
#Html.TextBoxFor(s=>s.EstimatedAmount)
#Html.HiddenFor(s=>s.JobSheetNo)
<input type="submit" />
}
So when user posts the form, we need to read the data from our viewmodel object and use that for saving
[HttpPost]
public ActionResult Edit(ComplantDetailVm model)
{
if(ModelState.IsValid)
{
var e=db.COMPLAINs.FirstOrDefault(s=>s.JOBSHEET_NO==model.JobSheetNo);
if(e!=null)
{
// Update the property values
e.CompanyName = model.CompanyName;
//Map other properties also
db.Entry(e).State = EntityState.Modified;
db.SaveChanges();
//to do : Redirect to Success message page.
}
}
return View(model);
}

Better Way To Edit A View Model in MVC

I actually came up with a working example of how to display (GET) and edit (POST) a view model consisting of three models in MVC. However, my MVC skills are limited and I was looking for suggestions on "the right way" I should be doing this.
The part in question is that I'm sending the form fields back individually rather than to a view model, which is something I couldn't figure out how to do.
Here are my models
Name
public partial class Name
{
public Name()
{
this.Addresses = new HashSet<Address>();
this.Emails = new HashSet<Email>();
}
public int ID { get; set; }
public string FIRST_NAME { get; set; }
public string LAST_NAME { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
public virtual ICollection<Email> Emails { get; set; }
}
Address
public partial class Address
{
public int ADDRESS_ID { get; set; }
public int NameID { get; set; }
public string ADDRESS_1 { get; set; }
public string CITY { get; set; }
public string STATE { get; set; }
public string ZIP { get; set; }
public virtual Name Name { get; set; }
}
Email
public partial class Email
{
public int EMAIL_ID { get; set; }
public int NameID { get; set; }
public string EMAIL { get; set; }
public virtual Name Name { get; set; }
}
My View Model made up of all the fields from the three models.
public class ContactFormViewModel
{
public int? ID { get; set; }
public string FIRST_NAME { get; set; }
public string LAST_NAME { get; set; }
public string ADDRESS_1 { get; set; }
public string CITY { get; set; }
public string STATE { get; set; }
public string ZIP { get; set; }
public string EMAIL { get; set; }
}
The GET method of the Edit page (in the Controller)
// GET: Names/Edit/5
//The GET method takes the id from the URL and passes it into the query to return data for the specific record
public ActionResult Edit(int id)
{
//This query is an outer join of the Name, Address and Email models/tables
var query = from n in db.Names
join a in db.Addresses
on n.ID equals a.NameID into na
from a in na.DefaultIfEmpty()
join e in db.Emails
on n.ID equals e.NameID into ne
from e in ne.DefaultIfEmpty()
where n.ID == id
//Creates a new instance of the view model, populated with the query data
select new ContactFormViewModel
{
ID = id,
FIRST_NAME = n.FIRST_NAME,
LAST_NAME = n.LAST_NAME,
ADDRESS_1 = a.ADDRESS_1,
CITY = a.CITY,
STATE = a.STATE,
ZIP = a.ZIP,
EMAIL = e.EMAIL
};
//Returns the query to the view
return View(query);
}
The POST method of the Edit page (in the Controller)
// POST: Names/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
//The POST method takes the individual form field data and passes it to queries that update all three models separately
public ActionResult Edit(int id, string FIRST_NAME, string LAST_NAME, string ADDRESS_1, string CITY, string STATE, string ZIP, string EMAIL)
{
if (ModelState.IsValid)
{
//Query the database for the row to be updated.
var queryN =
from n in db.Names
where n.ID == id
select n;
var queryA =
from a in db.Addresses
where a.NameID == id
select a;
var queryE =
from e in db.Emails
where e.NameID == id
select e;
//Assign the form field data to the fields in the model
foreach (Name n in queryN)
{
n.FIRST_NAME = FIRST_NAME;
n.LAST_NAME = LAST_NAME;
}
//If there are no address records, insert
if (!queryA.Any())
{
//New instance of Address
var address = new Address
{
NameID = id,
ADDRESS_1 = ADDRESS_1,
CITY = CITY,
STATE = STATE,
ZIP = ZIP
};
db.Addresses.Add(address);
}
//Else, if there are address records, then update
else
{
foreach (Address a in queryA)
{
a.ADDRESS_1 = ADDRESS_1;
a.CITY = CITY;
a.STATE = STATE;
a.ZIP = ZIP;
}
}
//If there are no email records, insert
if (!queryE.Any())
{
//New instance of Email
var email = new Email
{
NameID = id,
EMAIL = EMAIL
};
db.Emails.Add(email);
}
//Else, if there are email records, then update
else
{
foreach (Email e in queryE)
{
e.EMAIL = EMAIL;
}
}
//// Submit the changes to the database.
try
{
db.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex);
// Provide for exceptions.
}
}
return RedirectToAction("Index");
}
The View
#model IQueryable<MDTestApplication.ViewModel.ContactFormViewModel>
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Name</h4>
<hr />
#*Uses foreach loop to get all field data from the view model*#
#foreach (var item in Model)
{
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(modelItem => item.ID)
<div class="form-group">
#Html.LabelFor(modelItem => item.FIRST_NAME, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#*Using razor syntax to output the value*#
#*Using form field 'Name' attribute for posting back to the controller*#
<input type="text" name="FIRST_NAME" value="#item.FIRST_NAME" class="form-control" />
</div>
</div>
<div class="form-group">
#Html.LabelFor(modelItem => item.LAST_NAME, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="text" name="LAST_NAME" value="#item.LAST_NAME" class="form-control" />
</div>
</div>
<div class="form-group">
#Html.LabelFor(modelItem => item.ADDRESS_1, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="text" name="ADDRESS_1" value="#item.ADDRESS_1" class="form-control" />
</div>
</div>
<div class="form-group">
#Html.LabelFor(modelItem => item.CITY, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="text" name="CITY" value="#item.CITY" class="form-control" />
</div>
</div>
<div class="form-group">
#Html.LabelFor(modelItem => item.STATE, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="text" name="STATE" value="#item.STATE" class="form-control" />
</div>
</div>
<div class="form-group">
#Html.LabelFor(modelItem => item.ZIP, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="text" name="ZIP" value="#item.ZIP" class="form-control" />
</div>
</div>
<div class="form-group">
#Html.LabelFor(modelItem => item.EMAIL, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="text" name="EMAIL" value="#item.EMAIL" class="form-control" />
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
UPDATE
Here's additional insert and update code I added to Alex's answer below. You would use this same setup for address and email.
foreach (var address in model.Addresses)
{
var addressToUpdate = name.Addresses.FirstOrDefault(a => AddressId== address.AddressId);
if (addressToUpdate != default(Address))
{
// preform an update
addressToUpdate.AddressId = address.AddressId;
addressToUpdate.City = address.City;
addressToUpdate.State = address.State;
addressToUpdate.Zip = address.Zip;
}
else
{
//perform an insert
var newAddress = new Address
{
NameID = model.ID,
Address1 = address.Address1,
City = address.City,
State = address.State,
Zip = address.Zip
};
db.Addresses.Add(newAddress);
}
}
First of all let me start with the naming convention.
This:
public int ADDRESS_ID { get; set; }
public int NameID { get; set; }
Is BAD You have no naming convention at all, some properties are PascalCase, others capital case with underscores. I strongly advise you to install some tool that will enforce you to apply set of style and consistency rules(for example StyleCop). In general it is very common to use PascalCase for properties.
Once you apply it your models will look like:
public partial class Address
{
public int AddressId { get; set; }
public int NameId { get; set; }
public string Address1 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public virtual Name Name { get; set; }
}
Second thing:
If I understand correct you are trying to edit a data for one user:
His(or hers) first and last name, list of addresses and a lit of emails. If I am right both your View and ViewModel are wrong. Your ViewModel could look as following:
public class ContactFormViewModel
{
public int NameId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<Address> Addresses { get; set; }
public IList<Emails> { get; set; }
}
Controller(UPDATED):
// GET: Names/Edit/5
//The GET method takes the id from the URL and passes it into the query to
//return data for the specific record
public ActionResult Edit(int id)
{
//You don't need the joins since you have navigation properies!
var name = db.Names.FirstOrDefault(n => n.ID == id);
ContactFormViewModel model;
if(name == default(Name))
{
model = new ContactFormViewModel{
Addresses = new List<Address>(),
Emails = new List<Email>()
};
}
else {
model = new ContactFormViewModel
{
NameId = name.NameId ,
FirstName = name.FirstName,
LastName = name.LastName ,
Addresses = name.Addresses.ToList(),
Emails = name.Emails.ToList(),
};
}
if(!model.Addresses.Any())
{
model.Addresses.Add(new Address());
}
if(!model.Emails.Any())
{
model.Emails.Add(new Email());
}
//Returns the query to the view
return View(model);
}
View:
#model MDTestApplication.ViewModel.ContactFormViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Name</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.NameId)
<div class="form-group">
#Html.LabelFor(model => model.FirstName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FirstName, new { #class = "FirstName" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.LastName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => item.LastName, new { #class = "FirstName" })
</div>
</div>
#for (int i = 0; i < Model.Addresses.Count; i++)
{
#Html.HiddenFor(model => model.Addresses[i].AddressId)
<div class="form-group">
#Html.LabelFor(model => model.Addresses[i].Address1, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Addresses[i].Address1, new { #class = "FirstName" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Addresses[i].City, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Addresses[i].City, new { #class = "FirstName" })
</div>
</div>
/// Continue here with all the address properties
}
#for (int i = 0; i < Model.Emails.Count; i++)
{
#Html.HiddenFor(model => model.Emails[i].EmailId)
<div class="form-group">
#Html.LabelFor(model => model.Emails[i].Email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Emails[i].Email, new { #class = "FirstName" })
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Edit Action in Controller:
public ActionResult Edit(ContactFormViewModel model)
{
if (ModelState.IsValid)
{
//Query the database for the row to be updated.
var name = db.Names.FirstOrDefault( n => n.NameId == model.NameId);
if(name != default(Name))
{
name.FirstName = model.FirstName;
name.LastName = model.LastName;
bool hasAddresses = name.Addresses.Any();
foreach(var address in model.Addresses)
{
var addressToUpdate = name.Addresses.FirstOrDefault(a => a.AddressId == address.AddressId);
if(addressToUpdate != default(Address))
{
// preform an update
}
else
{
//perform an insert
}
}
foreach(var email in model.Emails)
{
var emailToUpdate = name.Emails.FirstOrDefault(a => a.EmailId == email.EmailId);
if(emailToUpdate != default(Email))
{
// preform an update
}
else
{
//perform an insert
}
}
db.SaveChanges();
}
}
}
What you are attempting to do is submit a variable length list, which is not something asp mvc can handle on its own. Let me explain:
You have a form, and inside the form is a foreach loop that creates editable fields for multiple records. ASP MVC can handle updating a single record just fine with its form helpers, however when you have multiple records that need updating, ASP MVC doesn't automatically create an indexing number for each record, which makes it impossible for it to keep track of which property belongs to which record. When you submit the form, MVC doesn't create this indexing for you, so you need to find alternative solutions.
I highly suggest you look at this blog and incorporate the helper that is provided to achieve your form submission:
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

Resources