Working on my project I faced a problem: EF didn't load the data from connected table, but in other practically equal piece of code all is perfect. Can somebody explain it?
Here is the situation:
All is good, type.name is loaded:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult pacientEdit([Bind(Include = "ID,comments")] Anamnesis anamnesis)
{
if (ModelState.IsValid)
{
db.Entry(anamnesis).State = EntityState.Modified;
db.SaveChanges();
return pacientDetails(anamnesis.ID);
}
return PartialView(anamnesis);
}
public ActionResult pacientDetails(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Anamnesis anamnesis = db.anamneses.Include(p => p.type).Where(p => p.ID == id).First();
if (anamnesis == null)
{
return HttpNotFound();
}
return PartialView("~/views/Anamnesis/pacientDetails.cshtml", anamnesis);
}
Here I run PacientEdit, then it flows to PacientDetails and gives me full anamnesis, including full type with it's name.
All is bad, type.name is null:
In the second case the name of type is null despite all my tries to load it from db.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult pacientEdit(Assigment assigment)
{
if (ModelState.IsValid)
{
db.Entry(assigment).State = EntityState.Modified;
db.SaveChanges();
return pacientDetails(assigment.ID);
//dirty fix, but works: return (new AssigmentsController()).pacientDetails(assigment.ID);
}
return PartialView(assigment);
}
public ActionResult pacientDetails(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Assigment assigment = db.assigments.Include(p => p.type).Where(p => p.ID == id).First();
if (assigment == null)
{
return HttpNotFound();
}
return PartialView("~/views/Assigments/pacientDetails.cshtml", assigment);
}
In this case all data in pacientDetails, including type_ID is loading, but type.name is null
Can somebody explain such behavior?
Used models:
public class Anamnesis
{
public int ID { get; set; }
public AnamnesisEventType type { get; set; }
public String comments { get; set; }
}
public class Assigment
{
public int ID { get; set; }
public AssigmentType type { get; set; }
public decimal? weight { get; set; }
public decimal? dose { get; set; }
public decimal? inADay { get; set; }
[DataType(DataType.MultilineText)]
public String comments { get; set; }
public String medicine { get; set; }
[DefaultValue(1)]
public int actual { get; set; }
public DateTime cancelDate { get; set; }
}
public class AnamnesisEventType
{
public int ID { get; set; }
public String name { get; set; }
}
public class AssigmentType
{
public int ID { get; set; }
public String name { get; set; }
public String description { get; set; }
}
Here is the view for pacientEdit for AssigmentsController:
#model WebApplication2.Models.Assigment
<form id="#String.Format("AssigmentsEdit{0}", Model.ID)">
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.ID)
#Html.HiddenFor(model => model.type.ID)
#Html.HiddenFor(model => model.cancelDate)
#Html.HiddenFor(model => model.actual)
<div class="row">
<div class="col-md-4">
<strong>
#Html.DisplayFor(model => model.type.name)
</strong>
</div>
<div class="col-md-6">
<p>
#Html.EditorFor(model => model.medicine, new { htmlAttributes = new { #class = "form-control", #placeholder = Html.DisplayNameFor(model => model.medicine) } })
</p>
</div>
<div class="col-md-2">
<a onclick="CancelEdit('Assigments', #Model.ID);" class="btn btn-warning btn-sm"><span class="glyphicon glyphicon-backward" aria-hidden="true"></span></a>
<a class="btn btn-sm btn-primary" onclick="PostEditForm('Assigments', #Model.ID);">
<span class="glyphicon glyphicon-save" aria-hidden="true"></span>
</a>
</div>
</div>
<div class="row alert alert-info" style="margin-top:10px">
<div class="col-md-4">
<h4><span class="glyphicon glyphicon-tint" aria-hidden="true"></span> Назначение:</h4>
#Html.EditorFor(model => model.weight, new { htmlAttributes = new { #class = "form-control", #placeholder = Html.DisplayNameFor(model => model.weight) } })
#Html.EditorFor(model => model.dose, new { htmlAttributes = new { #class = "form-control", #placeholder = Html.DisplayNameFor(model => model.dose) } })
#Html.EditorFor(model => model.inADay, new { htmlAttributes = new { #class = "form-control", #placeholder = Html.DisplayNameFor(model => model.inADay) } })
</div>
<div class="col-md-8">
<h4><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> #Html.DisplayNameFor(model => model.comments):</h4>
<p>#Html.EditorFor(model => model.comments, new { htmlAttributes = new { #class = "form-control", #placeholder = Html.DisplayNameFor(model => model.comments) } })</p>
</div>
</div>
</form>
<hr />
I guess the problem is in the fact that you're trying to bind Assignment ID and AssignmentType ID using the same name.
Create an AssignmentViewModel class (which is anyway a good practice), where you'll have only the ID of member "type" like this:
public class AssigmentViewModel
{
public int ID { get; set; }
public int TypeId { get; set; }
public decimal? weight { get; set; }
public decimal? dose { get; set; }
public decimal? inADay { get; set; }
[DataType(DataType.MultilineText)]
public String comments { get; set; }
public String medicine { get; set; }
public int actual { get; set; }
public DateTime cancelDate { get; set; }
}
You could also try to modify the hiddenFor type like this:
#Html.HiddenFor(model => model.type)
Hope this help
Related
I am having a really werid issue my model is not binding to form correctly
#using (Html.BeginForm("SaveCaseNotes", "MISObjects", FormMethod.Post, new { #id = "myForm", #name = "myForm" })) {
<form id="myForm" asp-action="">
<div asp-validation-summary="All" class="text-danger"></div>
#Html.HiddenFor(m => m.Id)
#Html.LabelFor(model => model.Title)
#Html.TextBoxFor(model => model.Title, new { #class = "form-control", #placeholder = "Title" })
#Html.ValidationMessageFor(m => m.Title, string.Empty, new { #style = "color:red;" })
#Html.LabelFor(model => model.Summary)
#Html.TextBoxFor(model => model.Summary, new { #class = "form-control"})
#Html.ValidationMessageFor(m => m.Summary, string.Empty, new { #style = "color:red;" })
#Html.LabelFor(model => model.Notes)
#Html.EditorFor(model => model.Notes, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Notes)
#Html.LabelFor(model => model.DateReported)
#Html.EditorFor(model => model.DateReported, new { htmlAttributes = new { #class = "form-control datetimepicker" } })
#Html.ValidationMessageFor(model => model.DateReported)
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
<div class="modal-footer">
<button type="submit" id="btnSave" class="btn btn-primary">Save</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</form>
}
This is my model
public class MISObjectNotes {
public int Id { get; set; }
public int MISObjectId { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public string Notes { get; set; }
public string LastModifiedBy { get; set; }
public DateTime LastModifedDate { get; set; }
public DateTime DateReported { get; set; }
public DateTime DateActioned { get; set; }
public DateTimeOffset CreatedDate { get; set; }
public string CreatedBy { get; set; }
public bool isAcitve { get; set; }
public bool isDeleteted { get; set; }
}
This is my method but its not binding correctly from the above form btw the above form is behind1 render a partial inside a modal popup.
[HttpPost]
public async Task<IActionResult> SaveCaseNotes(MISObjectNotes notes) {
MISObject tempObject = new MISObject();
Int32.TryParse(HttpContext.Session.GetString("CaseId"),out int resultCaseId);
if (ModelState.IsValid) {
notes.MISObjectId = resultCaseId;
notes.isAcitve = true;
notes.LastModifedDate = DateTime.Now;
var test = notes.Notes;
notes.LastModifiedBy = HttpContext.Session.GetString("Intitals");
_context.Add(notes);
await _context.SaveChangesAsync();
tempObject = await _context.MISobject.Where(w=>w.Id== resultCaseId).FirstOrDefaultAsync();
}
return View("Details",tempObject);
}
You added your model to _context:
_context.Add(notes);
so you should take it from _context, and not from _context.MISobject.
tempObject = await _context.Where(w=>w.Id== resultCaseId).FirstOrDefaultAsync();
or did I missed something?
This is my method but its not binding correctly from the above form
[HttpPost]
public async Task<IActionResult> SaveCaseNotes(MISObjectNotes notes)
Based on the code you shared, we can find that you named action parameter with "notes", and you defined a property public string Notes { get; set; } in model class MISObjectNotes, which cause model binding not working as expected.
To fix it, you can try to rename your action parameter, such as "mISObjectNotes" etc.
I have a many-to-many relationship between User and Task model. I want to assign tasks to users when I am creating a new task. Because of that I created UserViewModel and CheckBoxView model. But now I can just assign tasks to users when I am editing a user table. I know I have to change UserController's Create action but I do not know how.
Here is my code:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public virtual ICollection<UserToTask> UserToTasks { get; set; }
}
public class Task
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<UserToTask> UserToTasks { get; set; }
}
public class UserToTask
{
public int Id { get; set; }
public int UserId { get; set; }
public int TaskId { get; set; }
public virtual User User { get; set; }
public virtual Task Task { get; set; }
}
public class CheckBoxViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Checked { get; set; }
}
public class UserViewModel
{
public int UserId { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public List<CheckBoxViewModel> Tasks { get; set; }
}
User Controller:
public class UsersController : Controller
{
private MyModel db = new MyModel();
// GET: Users
public ActionResult Index()
{
return View(db.Users.ToList());
}
// GET: Users/Create
public ActionResult Create()
{
return View();
}
// POST: Users/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,Surname")] User user)
{
if (ModelState.IsValid)
{
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
// GET: Users/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
User user = db.Users.Find(id);
if (user == null)
{
return HttpNotFound();
}
var result = from a in db.Tasks
select new
{
a.Id,
a.Title,
Checked = (from ab in db.UserToTasks
where (ab.UserId == id) & (ab.TaskId == a.Id)
select ab).Any()
};
var MyViewModel = new UserViewModel();
MyViewModel.UserId = id.Value;
MyViewModel.Name = user.Name;
MyViewModel.Surname = user.Surname;
var MyCheckBoxList = new List<CheckBoxViewModel>();
foreach (var item in result)
{
MyCheckBoxList.Add(new CheckBoxViewModel{Id = item.Id, Name = item.Title, Checked = item.Checked});
}
MyViewModel.Tasks = MyCheckBoxList;
return View(MyViewModel);
}
// POST: Users/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(UserViewModel user)
{
if (ModelState.IsValid)
{
var MyUser = db.Users.Find(user.UserId);
MyUser.Name = user.Name;
MyUser.Surname = user.Surname;
foreach (var item in db.UserToTasks)
{
if (item.UserId == user.UserId)
{
db.Entry(item).State = EntityState.Deleted;
}
}
foreach (var item in user.Tasks)
{
if (item.Checked)
{
db.UserToTasks.Add(new UserToTask() {UserId = user.UserId, TaskId = item.Id});
}
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
}
Edit view:
#model ItalianCoach.Models.UserViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>User</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.UserId)
<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.Surname, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Surname, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Surname, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Tasks, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#for (int i = 0; i < Model.Tasks.Count(); i++)
{
#Html.EditorFor(m => m.Tasks[i].Checked)
#Html.DisplayFor(m => m.Tasks[i].Name)<br/>
#Html.HiddenFor(m => m.Tasks[i].Name)
#Html.HiddenFor(m => m.Tasks[i].Id)
}
</div>
</div>
</div>
}
You do not need the UserToTask class. The relationships between them should be with the object classes themselves.
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public int TaskId { get; set; }
public virtual Task Task { get; set; }
public virtual ICollection<Task> Tasks { get; set; }
}
public class Task
{
public int Id { get; set; }
public string Title { get; set; }
}
You add in the TaskId as foreign key in the User class. Each User will have a collection of Tasks (which may or may not be empty - so be careful with your constructors).
To find all the Users for a particular Task - you use a database query on Users -> where TaskId == Task.Id.
You'll need to sort out the xaml, controllers, etc, to fit the new model.
I'm having trouble understanding how to retrieve data from my Device table in my database to a CheckBoxList.
I believe I have the Models, ViewModel and Database setup properly but I'm just not sure what to do next. For now, I would simple like to learn how to retrieve the data from my table to a CheckBoxList.
Customer Model
public class Customer
{
public int CustId { get; set; }
public string CustDisplayName { get; set; }
public string CustFirstName { get; set; }
public string CustLastName { get; set; }
public string CustCompanyName { get; set; }
public string CustAddress { get; set; }
public string CustPhoneNumber { get; set; }
public string CustMobileNumber { get; set; }
public string CustEmailAddress { get; set; }
public int StId { get; set; }
public State State { get; set; }
}
State Model
public class State
{
public int StId { get; set; }
public string StAbbr { get; set; }
public List<Customer> Customers { get; set; }
}
Device Model
public class Device
{
public int DevId { get; set; }
public string DevType { get; set; }
public bool isChecked { get; set; }
}
CustomerDevice Model
public class CustomerDevice
{
public int CustId { get; set; }
public int DevId { get; set; }
public Customer Customer { get; set; }
public Device Device { get; set; }
}
CustomerViewModel
public class CustomerFormViewModel
{
public int CustId { get; set; }
[Required(ErrorMessage = "Enter Display Name")]
[Display(Name = "Display Name")]
[StringLength(100)]
public string CustDisplayName { get; set; }
[Display(Name = "First Name")]
[StringLength(50)]
public string CustFirstName { get; set; }
[Display(Name = "Last Name")]
[StringLength(50)]
public string CustLastName { get; set; }
[Display(Name = "Company Name")]
[StringLength(50)]
public string CustCompanyName { get; set; }
[Display(Name = "Phone Number")]
[DataType(DataType.PhoneNumber)]
[StringLength(12)]
public string CustPhoneNumber { get; set; }
[Display(Name = "Mobile Number")]
[DataType(DataType.PhoneNumber)]
[StringLength(12)]
public string CustMobileNumber { get; set; }
[Display(Name = "Email Address")]
[DataType(DataType.EmailAddress)]
[StringLength(320)]
public string CustEmailAddress { get; set; }
[Required(ErrorMessage = "Enter Address")]
[Display(Name = "Address")]
[StringLength(100)]
public string CustAddress { get; set; }
[Required(ErrorMessage = "Select State")]
[Display(Name = "State")]
public int StId { get; set; }
public IEnumerable<State> States { get; set; }
}
CustomerController
public class CustomerController : Controller
{
private CoreWebAppContext _context;
public CustomerController(CoreWebAppContext context)
{
_context = context;
}
// GET: /<controller>/
public IActionResult Index()
{
return View(_context.Customers.ToList());
}
public ActionResult Create()
{
var states = _context.States.ToList();
var viewModel = new CustomerFormViewModel
{
States = states
};
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CustomerFormViewModel vm)
{
if (ModelState.IsValid)
{
var customer = new Customer();
{
customer.CustDisplayName = vm.CustDisplayName;
customer.CustFirstName = vm.CustFirstName;
customer.CustLastName = vm.CustLastName;
customer.CustCompanyName = vm.CustCompanyName;
customer.CustAddress = vm.CustAddress;
customer.CustPhoneNumber = vm.CustPhoneNumber;
customer.CustMobileNumber = vm.CustMobileNumber;
customer.CustEmailAddress = vm.CustEmailAddress;
customer.StId = vm.StId;
}
_context.Customers.Add(customer);
_context.SaveChanges();
return RedirectToAction("Index");
}
else
{
vm.States = _context.States.ToList();
return View(vm);
}
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var customervm = new CustomerFormViewModel();
{
Customer customer = _context.Customers.SingleOrDefault(c => c.CustId == id);
if (customer == null)
{
return NotFound();
}
customervm.CustId = customer.CustId;
customervm.CustDisplayName = customer.CustDisplayName;
customervm.CustFirstName = customer.CustFirstName;
customervm.CustLastName = customer.CustLastName;
customervm.CustCompanyName = customer.CustCompanyName;
customervm.CustAddress = customer.CustAddress;
customervm.CustPhoneNumber = customer.CustPhoneNumber;
customervm.CustMobileNumber = customer.CustMobileNumber;
customervm.CustEmailAddress = customer.CustEmailAddress;
// Retrieve list of States
var states = _context.States.ToList();
customervm.States = states;
// Set the selected state
customervm.StId = customer.StId;
}
return View(customervm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(CustomerFormViewModel vmEdit)
{
if (ModelState.IsValid)
{
Customer customer = _context.Customers.SingleOrDefault(c => c.CustId == vmEdit.CustId);
if (customer == null)
{
return NotFound();
}
customer.CustDisplayName = vmEdit.CustDisplayName;
customer.CustFirstName = vmEdit.CustFirstName;
customer.CustLastName = vmEdit.CustLastName;
customer.CustCompanyName = vmEdit.CustCompanyName;
customer.CustAddress = vmEdit.CustAddress;
customer.CustPhoneNumber = vmEdit.CustPhoneNumber;
customer.CustMobileNumber = vmEdit.CustMobileNumber;
customer.CustEmailAddress = vmEdit.CustEmailAddress;
customer.StId = vmEdit.StId;
_context.Entry(customer).State = EntityState.Modified;
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(vmEdit);
}
}
Create View
<div class="form-group">
#Html.LabelFor(c => c.CustDisplayName)
#Html.TextBoxFor(c => c.CustDisplayName, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustDisplayName)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustFirstName)
#Html.TextBoxFor(c => c.CustFirstName, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustLastName)
#Html.TextBoxFor(c => c.CustLastName, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustCompanyName)
#Html.TextBoxFor(c => c.CustCompanyName, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustAddress)
#Html.TextBoxFor(c => c.CustAddress, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustAddress)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustPhoneNumber)
#Html.TextBoxFor(c => c.CustPhoneNumber, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustPhoneNumber)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustMobileNumber)
#Html.TextBoxFor(c => c.CustMobileNumber, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustMobileNumber)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustEmailAddress)
#Html.TextBoxFor(c => c.CustEmailAddress, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustEmailAddress)
</div>
<div class="form-group">
#Html.LabelFor(s => s.StId)
#Html.DropDownListFor(s => s.StId, new SelectList(Model.States, "StId", "StAbbr"), "", new { #class = "form-control" })
#Html.ValidationMessageFor(s => s.StId)
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
Make another ViewModel class called IndexViewModel and put this on it:
public class IndexViewModel
{
public List<Customer> Customers { get; set; }
public List<Device> Devices { get; set; }
}
Here is your controller Action. Return the new IndexViewModel instead:
// GET: /<controller>/
public IActionResult Index()
{
return View(_context.Customers.ToList());
}
to
// GET: /<controller>/
public IActionResult Index()
{
var model = new IndexViewModel();
model.Customers = _context.Customers.ToList();
model.Devices = _context.Devices.ToList();
return View(model);
}
In your view, simply iterate the Device list:
#{
for(int i = 0; i < Model.Devices.Count(); i++)
{
var checkboxAttributes = Model.Devices[i].isChecked == true ?
(object) new { #class = "checkbox", #checked = "checked" } :
(object) new { #class = "checkbox" };
#Html.CheckBoxFor(model => model.Devices[i].DevType, checkboxAttributes)
#Html.LabelFor(model => model.Devices[i].DevType, new { #class = "label" })
}
}
Update 1
I'm sorry about the previous one but this is the correct version: It uses bootstrap style for the checkbox:
#{
for (int i = 0; i < Model.Devices.Count(); i++)
{
<div class="checkbox">
<label>
#Html.HiddenFor(model => model.Devices[i].DevId)
#Html.CheckBoxFor(model => model.Devices[i].isChecked)
#Html.DisplayFor(model => model.Devices[i].DevType)
#Html.HiddenFor(model => model.Devices[i].DevType)
</label>
</div>
}
}
You can use something like this, so you can reuse it for different models.
CheckboxViewModel:
public class CheckboxViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Checked { get; set; }
}
Extension method:
public static IEnumerable<CheckboxViewModel> CreateCheckboxList<T>(this List<T> entities, Func<T, object> value, Func<T, object> text, Func<T, bool> isChecked)
{
return entities.Select(x => new CheckboxViewModel
{
Id = (int)value(x),
Name = text(x).ToString(),
Checked = isChecked(x)
});
}
Using example:
result = devices.CreateCheckboxList(x => x.Id, x => x.Name, x => selectedDevices.Contains(x.Id)).ToList();
#for (var deviceIndex = 0; deviceIndex < Model.Devices.Count(); deviceIndex ++)
{
<div class="form-group">
<div class="checkbox checkbox-primary">
#Html.HiddenFor(model => model.Devices[deviceIndex ].Id)
#Html.CheckBoxFor(model => model.Devices[deviceIndex ].Checked)
#Html.LabelFor(model => model.Devices[deviceIndex ].Checked, Model.Devices[deviceIndex ].Name)
</div>
</div>
}
i'm new to asp.net mvc and i would like to know why ModelState.IsValid=false ??
in edit view when using
if (ModelState.IsValid)
{
//code
}
the complete code listed here:
model classes:
public class Departments
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Employeesss { get; set; }
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string City { get; set; }
public int DepartmentId { get; set; }
[ForeignKey("DepartmentId")]
public virtual Departments Id { get; set; }
}
public class dropdownDbContext : DbContext
{
public DbSet<Departments> Departments { get; set; }
public DbSet<Employee> Employees { get; set; }
}
in controller these are the edit controller
public ActionResult Edit(int id = 0)
{
Employee employee = db.Employees.Find(id);
if (employee == null)
{
return HttpNotFound();
}
ViewBag.DepartmentId = new SelectList(db.Departments, "Id", "Name", employee.DepartmentId);
return View(employee);
}
//
// POST: /empttttttttttttttttt/Edit/5
[HttpPost]
public ActionResult Edit(Employee employee)
{
if (!ModelState.IsValid)
{
var errors = ModelState.SelectMany(x => x.Value.Errors.Select(z => z.Exception));
// Breakpoint, Log or examine the list with Exceptions.
}
if (ModelState.IsValid)
{
db.Entry(employee).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.DepartmentId = new SelectList(db.Departments, "Id", "Name", employee.DepartmentId);
return View(employee);
}
in view
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Employee</legend>
#Html.HiddenFor(model => model.EmployeeId)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.City)
#Html.ValidationMessageFor(model => model.City)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DepartmentId, "Id")
</div>
<div class="editor-field">
#Html.DropDownList("DepartmentId", String.Empty)
#Html.ValidationMessageFor(model => model.DepartmentId)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
it doesn't show error but the edit didn't work properly in this logic when using
if (ModelState.IsValid)
{
db.Entry(employee).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
and i would like to know why ModelState.IsValid=false ??
this is error snapshot
The parameter conversion from type 'System.String' to type 'dropdown.Models.Departments' failed because no type converter can convert between these types.
Change:
if (!ModelState.IsValid)
{
var errors = ModelState.SelectMany(x => x.Value.Errors.Select(z => z.Exception));
// Breakpoint, Log or examine the list with Exceptions.
}
To:
if (!ModelState.IsValid)
{
var errors = ModelState
.Where(x => x.Value.Errors.Count > 0)
.Select(x => new { x.Key, x.Value.Errors })
.ToArray();
}
Then you put your breakpoint on errors instead
EDIT:
Change your model like this:
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string City { get; set; }
[ForeignKey("Departments")]
public int DepartmentId { get; set; }
public virtual Departments department { get; set; }
}
I'm having trouble getting a proper list, for the property LookupData, every time I post a form back, the modelbinder always returns null for just that property. I think I have done everything correctly since LookupData and its objects seem to be correctly indexed when viewing the results in the formcollection.
They get named as below but the model binder doesn't seem to want to build the list and bind it back to the property:
"[2].LookupData.[0].Description",
"[2].LookupData.[0].Value",
"[2].LookupData.[1].Description",
"[2].LookupData.[1].Value" etc..
All I really want is to hide the whole LookupData property and get it back after I post a form back.
Reportparameter class:
public class ReportParameter
{
[RequiredIf("Required", true, ErrorMessage = "*")]
public string ParamValue { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string DefaultValue { get; set; }
public string CustomProperty { get; set; }
public string LookupQuery { get; set; }
public bool Enabled { get; set; }
public int MaxLength { get; set; }
public bool Required { get; set; }
public List<string> Dependence { get; set; }
public List<ILookupData> LookupData { get; set; }
public VariantType Type { get; set; }
public ReportType Destinations { get; set; }
}
LookupData class
public interface ILookupData
{
string Value { get; set; }
string Description { get; set; }
}
My view:
#model List<ReportParameter>
#section scripts{
<script>
jQuery(document).ready(function() {
$(".datepick").datepicker($.datepicker.regional["#ViewBag.LanguageCode"]);
});
</script>
}
#using (Html.BeginForm("Report", "Reports", FormMethod.Post))
{
<div id="searchpaneloptions" class="collapse in search-panel report-options">
<div class="row">
<div class="col-md-12">
<p class="pull-right lsf"><a class="close-options subtle" href="#">close</a></p>
<h2 id="options">#Metadata.Txt("Report options") <small class="option-heading">#if (ViewBag.ReportLabel != null){ #ViewBag.ReportLabel } </small></h2>
</div>
</div>
<div class="row">
#if (!Model.IsNullOrEmpty())
{
<div class="col-md-4 ">
#Html.EditorForModel()
</div>
}
</div>
<div class="clearfix space-before"></div>
</div>
}
Editortemplate for the ReportParameter, the part where I use #Html.EditorFor(model => model.LookupData, "Lookups"):
#model ReportParameter
#Html.HiddenFor(m => m.Name)
#Html.HiddenFor(m => m.Type)
#Html.HiddenFor(m => m.Title)
#Html.HiddenFor(m => m.CustomProperty)
#Html.HiddenFor(m => m.DefaultValue)
#Html.HiddenFor(m => m.Destinations)
#Html.HiddenFor(m => m.Enabled)
#Html.HiddenFor(m => m.LookupQuery)
#Html.HiddenFor(m => m.MaxLength)
#Html.HiddenFor(m => m.Required)
#Html.HiddenFor(m => m.Type)
#Html.ValidationSummary(true)
#{
Model.Dependence = new List<string>(){"aaa","3222","123"}; //testing string list, same problem here
}
#if (!Model.Dependence.IsNullOrEmpty())
{
#Html.EditorFor(model => model.Dependence,"Lookups2")//testing string list, same problem here
}
#if (Model.Required)
{
#Html.ValidationMessageFor(m => m.ParamValue, "*")
}
#if (Model.Type == VariantType.VT_Datetime || Model.Type == VariantType.VT_Date)
{
#Html.LabelFor(m => m.Name, Model.Title, new { #class = "xcol-lg-4 control-label" })
#Html.TextBoxFor(m => m.ParamValue, new { #class = "form-control input-lg datepick" })
}
else if (Model.Name != "destinationoptions")
{
#Html.LabelFor(m => m.Name, Model.Title, new { #class = "xcol-lg-4 control-label" })
if (Model.LookupData.IsNullOrEmpty())
{
#Html.TextBoxFor(m => m.ParamValue, new { #class = "form-control input-lg" })
}
else
{
#Html.DropDownListFor(model => model.ParamValue, Model.LookupData.ToSelectListItems(Model.ParamValue ?? Model.DefaultValue ?? ""))
#Html.EditorFor(model => model.LookupData, "Lookups")
}
}
Editortemplate for the lookupdata property
#model List<ILookupData>
#for (int i = 0; i < Model.Count; i++) {
#Html.EditorFor(m => m[i],"Lookup")
}
Editortemplate for the items in the lookupdata list
#model ILookupData
#Html.HiddenFor(m => m.Description)
#Html.HiddenFor(m => m.Value)
Well i solved my problem by wrapping the list in its own class. I could not get this to work without the list being a property. And as #Jakub pointed out i had to change the objecttype to a concrete class rather than using the interface.
public class ReportParameterLookup
{
public IList<DatLookupData> Lookup { get; set; }
}
public class ReportParameter
{
[RequiredIf("Required", true, ErrorMessage = "*")]
public string ParamValue { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string DefaultValue { get; set; }
public string CustomProperty { get; set; }
public string LookupQuery { get; set; }
public bool Enabled { get; set; }
public int MaxLength { get; set; }
public bool Required { get; set; }
public List<string> Dependence { get; set; }
public ReportParameterLookup LookupData { get; set; }
public VariantType Type { get; set; }
public ReportType Destinations { get; set; }
}
This lead to the following correct naming "[2].LookupData.Lookup[1].Description"