I have an MVC5 project with Entity 6 framework and I am having trouble getting the correct information passed to the edit action on the post, in order to bind it to the models. The ModelState of my viewModel comes back as invalid. I am not sure what I am missing. I am guessing that it has to do with the way that my Editor templates are setup vs the structure of my models but I need some help figuring it out. I have spent many hours changing things to try and get this working and I still cant get it corrected.
My ViewModel:
namespace CommunityHealth.Models.ViewModels
{
public class ActivityViewModel
{
public virtual IList<JunctionTypeAction> junctionTypeActions{ get; set; }
public virtual IList<JunctionDepartmentAction> junctionDepartmentActions{ get; set; }
public virtual IList<JunctionPopulationAction> junctionPopulationActions { get; set; }
public virtual CommunityAction Action { get; set; }
}
}
The Community Action Model:
public partial class CommunityAction
{
public CommunityAction()
{
this.JunctionPopulationActions = new HashSet<JunctionPopulationAction>();
this.JunctionDepartmentActions = new HashSet<JunctionDepartmentAction>();
this.JunctionTypeActions = new HashSet<JunctionTypeAction>();
}
public int ActionID { get; set; }
public System.DateTime StartDate { get; set; }
public Nullable<System.DateTime> EndDate { get; set; }
public string BreifDescription { get; set; }
public Nullable<int> Duration { get; set; }
public int LocationID { get; set; }
public string SubLocation { get; set; }
public int ProgramID { get; set; }
public string Notes { get; set; }
public string AddedBy { get; set; }
public byte[] RecordVersion { get; set; }
public virtual Location Location { get; set; }
public virtual Program Program { get; set; }
public virtual ICollection<JunctionPopulationAction> JunctionPopulationActions { get; set; }
public virtual ICollection<JunctionDepartmentAction> JunctionDepartmentActions { get; set; }
public virtual ICollection<JunctionTypeAction> JunctionTypeActions { get; set; }
}
The Models for the Junction Tables:
JunctionDepartmentAction:
public partial class JunctionDepartmentAction
{
public int IndexID { get; set; }
public int DepartmentID { get; set; }
public int ActionID { get; set; }
public string SubDepartment { get; set; }
public int Individuals { get; set; }
public virtual CommunityAction CommunityAction { get; set; }
public virtual Department Department { get; set; }
}
JunctionPopulationAction:
public partial class JunctionPopulationAction
{
public int IndexID { get; set; }
public int PopulationID { get; set; }
public int ActionID { get; set; }
public bool isActive { get; set; }
public virtual CommunityAction CommunityAction { get; set; }
public virtual TargetPopulation TargetPopulation { get; set; }
}
JunctionTypeAction:
public partial class JunctionTypeAction
{
public int IndexID { get; set; }
public int TypeID { get; set; }
public int ActionID { get; set; }
public virtual ActivityType ActivityType { get; set; }
public virtual CommunityAction CommunityAction { get; set; }
}
Event Controller Edit Action Methods:
// GET: /Event/Edit/5
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
CommunityAction communityaction = await db.CommunityActions.FindAsync(id);
ActivityViewModel activityviewmodel = new ActivityViewModel();
activityviewmodel.Action = communityaction;
IList<JunctionTypeAction> junctiontypeactions = await db.JunctionTypeActions.Where(d => d.ActionID == communityaction.ActionID).ToListAsync();
IList<JunctionDepartmentAction> junctiondepartmentactions = await db.JunctionDepartmentActions.Where(d => d.ActionID == communityaction.ActionID).ToListAsync();
IList<JunctionPopulationAction> junctionpopulationactions = await db.JunctionPopulationActions.Where(d => d.ActionID == communityaction.ActionID).ToListAsync();
activityviewmodel.junctionTypeActions = junctiontypeactions.ToList();
activityviewmodel.junctionDepartmentActions = junctiondepartmentactions.ToList();
activityviewmodel.junctionPopulationActions = junctionpopulationactions.ToList();
if (communityaction == null)
{
return HttpNotFound();
}
ViewBag.LocationID = new SelectList(db.Locations, "LocationID", "LocationName", activityviewmodel.Action.LocationID);
ViewBag.ProgramID = new SelectList(db.Programs, "ProgramID", "ProgramID", activityviewmodel.Action.ProgramID);
return View(activityviewmodel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(ActivityViewModel activity)
{
//request added for debugging purposes
Request.ToString();
if (ModelState.IsValid)
{
db.Entry(activity).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.LocationID = new SelectList(db.Locations, "LocationID", "LocationName", activity.Action.LocationID);
ViewBag.ProgramID = new SelectList(db.Programs, "ProgramID", "ProgramID", activity.Action.ProgramID);
return View(activity);
}
And finally my Views. I am using three editor templates for the junction tables in the DataBase and one more for the CommunityAction object. I then have a view for the event that uses the three editor templates to display the parts of the ViewModel.
CommunityAction.cshtml:
#model CommunityHealth.Models.CommunityAction
<div class="form-horizontal">
<h4>CommunityAction</h4>
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.ActionID)
#Html.HiddenFor(model => model.RecordVersion)
<div class="form-group">
#Html.LabelFor(model => model.StartDate, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.StartDate)
#Html.ValidationMessageFor(model => model.StartDate)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.EndDate, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.EndDate)
#Html.ValidationMessageFor(model => model.EndDate)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.BreifDescription, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BreifDescription)
#Html.ValidationMessageFor(model => model.BreifDescription)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Duration, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Duration)
#Html.ValidationMessageFor(model => model.Duration)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.LocationID, "Location", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.Location, ViewBag.LocationID as SelectList, new { htmlAttributes = new { #class = "control-form" } })
#Html.ValidationMessageFor(model => model.Location)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SubLocation, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SubLocation)
#Html.ValidationMessageFor(model => model.SubLocation)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ProgramID, "Program", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.ProgramID, ViewBag.ProgramID as SelectList, new { htmlAttributes = new { #class = "control-form" } })
#Html.ValidationMessageFor(model => model.Program)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Notes, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Notes)
#Html.ValidationMessageFor(model => model.Notes)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.AddedBy, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.AddedBy)
#Html.ValidationMessageFor(model => model.AddedBy)
</div>
</div>
<div class="form-group">
<div class="col-md-10">
</div>
</div>
</div>
JunctionTypeAction.cshtml:
#model CommunityHealth.Models.JunctionTypeAction
<div class="type">
<fieldset>
#Html.HiddenFor(model => model.ActionID)
#Html.HiddenFor(model => model.IndexID)
#Html.EditorFor(model => model.TypeID, "TypeName", new { #class = "control-label col-md-2" })
</fieldset>
</div>
JunctionDepartmentAction.cshtml:
#model CommunityHealth.Models.JunctionDepartmentAction
#using CommunityHealth.Models
<div>
<table>
<tbody>
<tr>
<td>
#Html.HiddenFor(model => model.ActionID)
#Html.HiddenFor(model => model.IndexID)
#Html.EditorFor(model => model.DepartmentID, "DepartmentName", new { #class = "control-label col-md-2" })
</td>
<td>
#Html.EditorFor(model => model.SubDepartment, "SubDepartment", new { #class = "control-label col-md-2 " })
</td>
<td>
#Html.EditorFor(model => model.Individuals)
</td>
</tr>
</tbody>
</table>
</div>
JunctionPopulationAction.cshtml:
#model CommunityHealth.Models.JunctionPopulationAction
<div class="population">
<fieldset>
#Html.HiddenFor(model => model.ActionID)
#Html.HiddenFor(model => model.IndexID)
#Html.EditorFor(model => model.PopulationID, "PopulationName", new { #class = "control-label col-md-2" })
</fieldset>
</div>
Views\Event\Edit.cshtml:
#model CommunityHealth.Models.ViewModels.ActivityViewModel
#using CommunityHealth.Models.ViewModels;
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm("Edit","Event",FormMethod.Post))
{
#Html.AntiForgeryToken()
<div>
<div class="form-group">
#Html.EditorFor(model => model.Action)
</div>
<div class="form-group">
#Html.Label("Types")
<div class="col-md-10">
<fieldset>
#for (int x = 0; x < Model.junctionTypeActions.Count(); x++)
{
#Html.EditorFor(model => model.junctionTypeActions[x])
}
</fieldset>
</div>
</div>
<div class="form-group">
#Html.Label("Departments")
<div class="col-md-10">
#for (int x = 0; x < Model.junctionDepartmentActions.Count(); x++)
{
#Html.EditorFor(model => model.junctionDepartmentActions[x])
}
</div>
</div>
<div class="form-group">
#Html.Label("Target Populations")
<div class="col-md-10">
#for (int x = 0; x < Model.junctionDepartmentActions.Count(); x++)
{
#Html.EditorFor(model => model.junctionPopulationActions[x])
}
</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>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I am getting this error when I examine the request:
"The parameter conversion from type 'System.String' to type 'CommunityHealth.Models.CommunityAction' failed because no type converter can convert between these types."
The reason for that error is because you model has a property named activity (typeof CommunityAction), and the parameter of your post method is also named activity. Change the parameter name to anything other than the name of a property in the model(s)
public async Task<ActionResult> Edit(ActivityViewModel model)
{
....
}
Side notes
Simply use #Html.EditorFor(m => m.junctionTypeActions) to generate
the html for collections (not in a for loop). #Html.EditorFor()
is smart enough to recognize collections and generate the correct
html.
Generating all those hidden inputs is bad practice and degrades
performance (and any malicious user could change the values anyway).
Use view models for each or your types that contain only the
properties you need to display/edit.
Related
i'm working with custom authentication with asp.net mvc , i'm using Role Provider. i have many to many relation User , Role , UserInRoles .
the error in binding roles values in checkboxs in view
i tried debugging controller create method it return all data in Role table then continue to view in foreach
error DataBinding: 'System.String' does not contain a property with the name 'Name'.
User Model
public class User
{
[Key]
public string UserId { get; set; }
public string Name { get; set; }
public virtual ICollection<UserInRoles> UserInRoles { get; set; }
}
Role Model
public class Role
{
public int RoleId { get; set; }
public string Name { get; set; }
public virtual ICollection<UserInRoles> UserInRoles { get; set; }
}
UserInRole Model
public class UserInRoles
{
[Key, Column(Order = 0)]
public string UserId { get; set; }
[Key, Column(Order = 1)]
public int RoleId { get; set; }
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
Controller
public ActionResult Create()
{
ViewBag.RoleId = new SelectList(Roles.GetAllRoles().ToList(), "Name", "Name");
return View();
}
View
#model AramexOneKnowledge.Models.RegisterViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>User</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.UserId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserId, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.UserId, "", new { #class = "text-danger" })
</div>
</div>
<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>
<div class="form-group">
<label class="col-md-2 control-label">
Select User Role
</label>
<div class="col-md-10">
#foreach (var item in (SelectList)ViewBag.RoleId)
{
<input type="checkbox" name="SelectedRoles"
value="#item.Value" class="checkbox-inline" />
#Html.Label(item.Value, new { #class = "control-label" })
}
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</div>
expected result display roles in checkbox
this exception because Roles.GetAllRoles() returns string[] and you try to bind property Name inside it which it not exists.
so to overcome this issue you can populate you checkbox list as following
ViewBag.RoleId = Roles.GetAllRoles().Select(r => new SelectListItem{Text = r, Value = r});
in this case you SelectListItem Value and Text it will be the role name for both of them
I am working on small ticket system for operations maintenance services comp.
Customer open a ticket and gives general information like location,
category description etc.
After technician fix the problem he must give sum details of the
problem from predefined set, use later for statistical reports.
My problem the repair method unable to post updated values to database plus nothing added to Defects_List table.
Note: I used this tutorial as guide
Models:
public partial class Tickets
{
public Tickets()
{
this.DefectsList = new HashSet<Defects_List>();
}
[Key]
[Display(Name = "Ticket Id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Ticket_Id { get; set; }
[Display(Name = "Project")]
public int Project_Id { get; set; }
[Display(Name = "Issue Date")]
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime Issue_Date { get; set; }
[Display(Name = "Category")]
[DisplayFormat(NullDisplayText = "[Not set]")]
public int Category_Id { get; set; }
//Other Properties Removed for clarity
public virtual Business_Category businessCategories { get; set; }
public virtual ICollection<Defects_List> DefectsList { get; set; }
}
public partial class Business_Category
{
public Business_Categories()
{
this.Tickets = new HashSet<Tickets>();
this.Malfunctions = new HashSet<Malfunctions>();
}
[Key]
[Display(Name="Category Id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Category_Id { get; set; }
[Display(Name = "Name (eng)")]
[StringLength(60, ErrorMessage = "Name cannot be longer than 60 characters.")]
public string Category_Name { get; set; }
public virtual ICollection<Tickets> Tickets { get; set; }
public virtual ICollection<Manufacturers> Manufacturers { get; set; }
public virtual ICollection<Malfunctions> Malfunctions { get; set; }
}
public partial class Defects_List
{
[Key, Column(Order = 0)]
[Display(Name = "Ticket Id")]
public int Ticket_Id { get; set; }
[Key, Column(Order = 1)]
[Display(Name = "Malfunction Id")]
public int Malfunction_Id { get; set; }
[StringLength(125, ErrorMessage = "Other cannot be longer than 125 characters.")]
public string Other { get; set; }
public virtual ICollection<Tickets> Tickets { get; set; }
public virtual Malfunctions Malfunctions { get; set; }
}
Controller:
// GET: /Tickets/Edit/5
public ActionResult Repair(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var tickets = db.nt_Tickets
.Include(t => t.DefectsList).Where(t => t.Ticket_Id == id)
.Single();
if (tickets == null)
{
return HttpNotFound();
}
PopulateSelectedDefects(tickets);
//Other codes Removed for clarity
return View(tickets);
}
private void PopulateSelectedDefects(nt_Tickets Tickets)
{
int categoryId;
if (Tickets.Category_Id == 2)
categoryId = 1;
else categoryId = Tickets.Category_Id;
var allDefects = (from m in db.sys_Malfunctions
where m.Category_Id == categoryId
select m).ToList();
var ticketDefects = new HashSet<int>(Tickets.DefectsList.Select(t => t.Malfunction_Id));
var viewModel = new List<TicketDefectsViewModel>();
foreach (var defect in allDefects)
{
viewModel.Add(new TicketDefectsViewModel
{
Malfunction_Id = defect.Malfunction_Id,
Malfunction_Name_e = defect.Malfunction_Name_e,
IsSelected = ticketDefects.Contains(defect.Malfunction_Id)
});
}
ViewBag.Defects = viewModel;
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Repair(int? id, string[] selectedDefects)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var ticketToUpdate = db.nt_Tickets
.Include(i => i.DefectsList)
.Where(i => i.Ticket_Id == id)
.Single();
if (TryUpdateModel(ticketToUpdate, "",
new string[] { Ticket_Id,Project_Id,Category_Id,Subject,Workshop_Id,Requested_By,Requestor_Mobile, Requestor_eMail,Location_Id,Ticket_Status,Periority_Id,Assigned_To,Description,Issue_Date,Created_By,Created_Date,Updated_By,Updated_Date" }))
{
ticketToUpdate.Updated_By = User.Identity.Name;
ticketToUpdate.Updated_Date = DateTime.UtcNow;
db.Entry(ticketToUpdate).State = EntityState.Modified;
SetTicketDefects(selectedDefects, ticketToUpdate);
try
{
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DbEntityValidationException dbEx)
{
Exception raise = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
string message = string.Format("{0}:{1}",
validationErrors.Entry.Entity.ToString(),
validationError.ErrorMessage);
if (!string.IsNullOrEmpty(message))
ViewBag.errorMessage = message;
}
return View("Error");
}
throw raise;
}
}
PopulateSelectedDefects(ticketToUpdate);
return View("Index");
}
private void SetTicketDefects(string[] selectedDefects, Tickets ticketToUpdate)
{
if (selectedDefects == null)
{
ticketToUpdate.DefectsList = new List<Defects_List>();
return;
}
var selectedDefectsHS = new HashSet<string>(selectedDefects);
var tcketDefects = new HashSet<int>
(ticketToUpdate.DefectsList.Select(c => c.Ticket_Id));
foreach (var defect in db.DefectsLists)
{
if (selectedDefectsHS.Contains(defect.Malfunction_Id.ToString()))
{
if (!tcketDefects.Contains(defect.Malfunction_Id))
{
ticketToUpdate.DefectsList.Add(defect);
}
}
else
{
if (tcketDefects.Contains(defect.Malfunction_Id))
{
ticketToUpdate.DefectsList.Remove(defect);
}
}
}
}
db.DefectsLists here [foreach (var defect in db.DefectsLists)] always empty.
Repair View:
#using (Html.BeginForm("Repair", "Tickets", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
#*#using (Html.BeginForm())*#
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Ticket_Id)
#Html.HiddenFor(model => model.Issue_Date)
#Html.HiddenFor(model => model.Created_By)
#Html.HiddenFor(model => model.Project_Id)
#Html.HiddenFor(model => model.Created_Date)
<div class="form-group">
#Html.Label("Ticket_Id", new { #class = "control-label col-md-2" })
<div class="col-md-1 " style="margin-top:7px">
#Html.DisplayFor(model => model.Ticket_Id)
</div>
#Html.LabelFor(model => model.Issue_Date, new { #class = "control-label col-md-2" })
<div class="col-md-2" style="margin-top:7px">
#Html.DisplayFor(model => model.Issue_Date, new { #class = "form-control" })
</div>
#Html.LabelFor(model => model.Category_Id, new { #class = "control-label col-md-2" })
<div class="col-md-3" style="margin-top:7px">
#Html.DropDownList("Category_Id", null, new { #class = "form-control", #disabled = "disabled" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Subject, new { #class = "control-label col-md-2" })
<div class="col-md-10" style="margin-top:7px">
#Html.DisplayFor(model => model.Subject, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Description, new { #class = "control-label col-md-2" })
<div class="col-md-10" style="margin-top:7px">
#Html.DisplayFor(model => model.Description, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Requested_By, new { #class = "control-label col-md-2" })
<div class="col-md-5" style="margin-top:7px">
#Html.DisplayFor(model => model.Requested_By, new { #class = "form-control" })
</div>
#Html.LabelFor(model => model.Requestor_Mobile, new { #class = "control-label col-md-2" })
<div class="col-md-3" style="margin-top:7px">
#Html.DisplayFor(model => model.Requestor_Mobile, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Requestor_eMail, new { #class = "control-label col-md-2" })
<div class="col-md-10" style="margin-top:7px">
#Html.DisplayFor(model => model.Requestor_eMail, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Ticket_Status, new { #class = "control-label col-md-2" })
<div class="col-md-4" style="margin-top:7px">
#Html.EnumDropDownListFor(model => model.Ticket_Status, new { #class = "form-control" })
</div>
#Html.LabelFor(model => model.Periority_Id, new { #class = "control-label col-md-2" })
<div class="col-md-4" style="margin-top:7px">
#Html.EnumDropDownListFor(model => model.Periority_Id, new { #class = "form-control", #disabled = "disabled" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Location_Id, new { #class = "control-label col-md-2" })
<div class="col-md-4">
#Html.DropDownList("Location_Id", null, new { #class = "form-control", #disabled = "disabled" })
#Html.ValidationMessageFor(model => model.Location_Id)
</div>
#Html.LabelFor(model => model.Assigned_To, new { #class = "control-label col-md-2" })
<div class="col-md-4">
#Html.DropDownList("Assigned_To", null, new { #class = "form-control", #disabled = "disabled" })
</div>
</div>
<div class="form-group">
<div class="col-md-10">
#Html.Label("Defects")
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<table class="table table-hover">
<tr>
#{
int cnt = 0;
List<MaintCare.ViewModels.TicketDefectsViewModel> defects = ViewBag.Defects;
foreach (var defect in defects)
{
if (cnt++ % 3 == 0)
{
#:</tr><tr>
}
#:<td>
<input type="checkbox"
name="selectedDefects"
value="#defect.Malfunction_Id"
#(Html.Raw(defect.IsSelected ? "checked=\"checked\"" : "")) />
#defect.Malfunction_Name_e
#:</td>
}
#:</tr>
}
</table>
</div>
</div>
<br />
<div class="form-group">
<div class="col-md-2">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
This question already has answers here:
What Causes The INSERT statement conflicted with the FOREIGN KEY constraint?
(2 answers)
Closed 6 years ago.
I'm working in ASP.NET MVC Web Application, so I want to insert values from another table (I get it with dropdownlist), but when I try to post, I get this:
The INSERT statement conflicted with the FOREIGN KEY constraint
"FK_dbo.Products_dbo.Subcategories_SubcategoryId". The conflict
occurred in database "ProyectName", table "dbo.Subcategories", column
'SubcategoryId'. The statement has been terminated.
Products model:
public class Product
{
public int ProductId { get; set; }
public int SubcategoryId { get; set; }
public virtual Subcategory Subcategory { get; set; }
public string Name { get; set; }
public string Presentation { get; set; }
public string Image { get; set; }
public string Alt { get; set; }
public bool IsDeleted { get; set; }
Product ViewModel
public class ProductViewModel
{
public string Name { get; set; }
public string Presentation { get; set; }
public string Image { get; set; }
public string Alt { get; set; }
public int SelectedSubcategory { get; set; }
public IEnumerable <SelectListItem> Subcategory { get; set; }
}
Subcategory Model:
public class Subcategory
{
public int SubcategoryId { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public string Alt { get; set; }
public string Pdf { get; set; }
public bool IsDeleted { get; set; }
public bool IsInstalled { get; set; }
}
Get Controller
public ActionResult Create()
{
var subcategoryList = new ProductViewModel
{
Subcategory = new SelectList(db.SubcategoriesList, "SubcategoryId", "Name")
};
return View(subcategoryList);
}
Post Controller(Service method):
public class ProductService : IProductService
{
private EfDatabase db = new EfDatabase();
public async Task<string> CreateProduct(ProductViewModel model)
{
var product = new Product
{
Name = model.Name,
Presentation = model.Presentation,
Image = model.Image,
Alt = model.Alt,
SubcategoryId = model.SelectedSubcategory,
IsDeleted = false
};
db.ProductsList.Add(product);
await db.SaveChangesAsync();
return "Product " + model.Name + "has been created";
View:
#model Proyect.Models.ViewModels.ProductViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Product</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.SubcategoryId, "SubcategoryId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.SelectedSubcategory, Model.Subcategory, "-Selecciona una opcion-", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.SelectedSubcategory)
</div>
</div>
<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>
<div class="form-group">
#Html.LabelFor(model => model.Presentation, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Presentation, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Presentation, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Image, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Image, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Image, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Alt, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Alt, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Alt, "", 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>
So I don't found any error on my code, what's wrong with that? can any one help me to solve this problem?
My question is unique because model.SelectedSubcategory don't get Id value from another table, It always get 0 so in the other questions no make any comparision with that
Thankyou in advance!
MY CREATE VIEW NOW
#model myPROYECT.Models.ViewModels.ProductViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Product</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-10">
#Html.DropDownListFor(m => m.SelectedSubcategory, Model.Subcategory, "-Selecciona una opcion-", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.SelectedSubcategory)
</div>
</div>
<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>
<div class="form-group">
#Html.LabelFor(model => model.Presentation, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Presentation, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Presentation, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Image, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Image, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Image, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Alt, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Alt, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Alt, "", 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>
There's nothing that requires a Subcategory to be selected. You're likely to get this error when a selection hasn't been made for subcategory. You should make subcategory required or make null a value that's possible to get back.
public class Product
{
public int ProductId { get; set; }
public int? SubcategoryId { get; set; }
public virtual Subcategory Subcategory { get; set; }
public string Name { get; set; }
public string Presentation { get; set; }
public string Image { get; set; }
public string Alt { get; set; }
public bool IsDeleted { get; set; }
}
using System.ComponentModel.DataAnnotations;
public class ProductViewModel
{
public int? SubcategoryId { get; set; }
public string Name { get; set; }
public string Presentation { get; set; }
public string Image { get; set; }
public string Alt { get; set; }
[Required]
public int? SelectedSubcategory { get; set; }
public IEnumerable Subcategory { get; set; }
}
Post Controller(Service method):
public class ProductService : IProductService
{
private EfDatabase db = new EfDatabase();
public async Task<string> CreateProduct(ProductViewModel model)
{
if (!ModelState.IsValid)
return View("Create");
var product = new Product
{
Name = model.Name,
Presentation = model.Presentation,
Image = model.Image,
Alt = model.Alt,
SubcategoryId = model.SelectedSubcategory,
IsDeleted = false
};
db.ProductsList.Add(product);
await db.SaveChangesAsync();
return "Product " + model.Name + "has been created";
}
}
I am currently working on a project to model a bikestore. In my 'Order' object, I have a lis object for the Bike items on the order. How would I add bikes to this list? I.E I want to display a list of availiable bikes in the Create view, an add one or more of them to the order.
My Controller:
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "OrderNumber,CustomerName,OrderDate,PickupDate,TotalCost,PaymentMethod")] Order order)
{
if (ModelState.IsValid)
{
db.Orders.Add(order);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(order);
}
My Inventory model
public class Inventory
{
public int Id { get; set; }
public string SerialNumber { get; set; }
public virtual Store Store { get; set; }
public int? StoreId { get; set; }
public string Model { get; set; }
public string Description { get; set; }
public Decimal InventoryCost { get; set; }
public Decimal RecSalePrice { get; set; }
public Decimal SalePrice { get; set; }
public string PaymentMethod { get; set; }
public virtual BikeCategory Category { get; set; }
public int? CategoryId { get; set; }
}
My Order model:
namespace BikeStore.Models
{
public class Order
{
public Order()
{
OrderedItems = new List<Inventory>();
}
public string CustomerName { get; set; } //FROM CONTROLLER User.Identity.Name
public virtual List<Inventory> OrderedItems { get; set; }
[Key, DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int OrderNumber { get; set; }
In the create view for orders:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Order</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.CustomerName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CustomerName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CustomerName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.OrderDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.OrderDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.OrderDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PickupDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PickupDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PickupDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TotalCost, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TotalCost, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.TotalCost, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PaymentMethod, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PaymentMethod, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PaymentMethod, "", 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>
Start by creating view models to represent what you want to display/edit in the view (add display and validation attributes as appropriate)
public class InventoryVM
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class OrderVM
{
public string PaymentMethod { get; set; }
public List<InventoryVM> Inventory { get; set; }
}
Note that CustomerName, OrderDate and Total are not appropriate (you don't want a user editing these - they should be set in the POST method immediately before saving the order). Not sure what PickupDate represents but if its the actual date then that's not appropriate either (it would be set separately when the order is collected). I would also suggest that PaymentMethod be an enum or collection of PaymentType's and that you and use a dropdownlist in the view for selection.
Then the GET method would be
public ActionResult Create()
{
// Get all available bikes, for example
var inventory = db.Inventory;
OrderVM model = new OrderVM
{
Inventory = inventory.Select(i => new
{
ID = i.ID,
Name = i.Model // modify this to suit what you want to display in the view
}).ToList()
};
return View(model);
}
And in the view
#model yourAssembly.OrderVM
#using (Html.BeginForm())
{
for(int i = 0; i < Model.Inventory.Count; i++)
{
#Html.HiddenFor(m => m.Inventory[i].ID)
#Html.CheckBoxFor(m => m.Inventory[i].IsSelected)
#Html.LabelFor(m => m.Inventory[i].IsSelected, Model.Inventory[i].Name)
}
#Html.TextBoxFor(m => m.PayentMethod)
<input type="submit" value="Create" />
}
And the POST method would be
public ActionResult Create(OrderVM model)
{
// Initialize a new Order and map properties from view model
var order = new Order
{
CustomerName = User.Identity.Name,
OrderDate = DateTime.Now,
....
PaymentMethod = model.PaymentMethod
}
// Save the order so that you now have its `ID`
IEnumerable<int> selectedItems = model.Inventory.Where(i => i.IsSelected).Select(i => i.ID);
foreach(var item in selectedItems)
{
// You have not shown the model for this so just guessing
var orderItem = new OrderItem{ OrderID = order.Id, InventoryId = item };
db.OrderItems.Add(orderItem);
}
db.SaveChanges();
}
Side notes:
If you want to be able to allow users to select more that one of any
item, the you could change bool IsSelected to say int Quantity
If you you want to display additional information about the items,
say Description and Cost you can include additional properties
in the InventoryVM view model and display them with
#Html.DisplayFor(m => m.Inventory[i].Description)
If you want to display a total cost for all selected items in the
view, you will need to use javascript/jquery
If ModelState could be invalid, you will need to repopulate the
properties of InventoryVM before you return the view (as shown
only the ID and IsSelected properties post back) or include
hidden inputs for the other properties in the view
How to save data from Select box in Entity Framework Database relation Many to Many
There are two classes one weapon and other User..
public class Weapon { } public class User { }
public class User
{
public int ID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
}
public class Wepon
{ public int ID { get; set; }
public string Wepon_Name { get; set; }
public int Power { get; set; }
}
Which should have relation Many to Many Using FormCollection and Model
User Class
And Weapon Class
public class User
{
public int ID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
**public List<Wepon> WeposInList { get; set; }**
}
public class Wepon
{
public int ID { get; set; }
public string Wepon_Name { get; set; }
public int Power { get; set; }
public List<User> UsersHaveWeponsList { get; set; }// User the List for M to M
}
DBContext
public class DbContexFor : DbContext
{
public DbContexFor()
: base("name=ConnectionStringName")
{
}
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Wepon> Wepons { get; set; }
}
}
**
The Controller Code
**
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Name,Type")] User user, FormCollection formData)
{
if (ModelState.IsValid)
{
var ss = formData["ShipFromCountries"].ToString();
user.WeposInList = db.Wepons.Where(c => c.Wepon_Name == ss).ToList();
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
And the Html Code
#model enumVarAction.Models.User
#{
var list = ViewBag.MyList;
ViewBag.Title = "Create";
}
Create Html Page
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>User</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>
<div class="form-group">
#Html.LabelFor(model => model.Type, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Type, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Type, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.WeposInList, htmlAttributes: new { #class = "control-label col-md-2" })
<select id="ShipFromCountries" multiple="multiple" name="ShipFromCountries">
<div class="col-md-10">
#foreach (var VARIABLE in list)
{
<option value="#VARIABLE.Wepon_Name">#VARIABLE.Wepon_Name</option>
}
</div>
</select>
</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")
}
**
Debug at Controller
**
**
Data is Database
**