Values on PostBack getting lost - asp.net-mvc-3

I am using MVC3 and classes generetad from EntityFranmework for saving some data into a Database.
The controller
// Get
public ActionResult Create(Guid StudentID)
{
Semester semester = new Semester();
ViewBag.BranchID = new SelectList(db.Branches, "ID", "Name");
semester.Student = db.Students.Single(s => s.ID == StudentID);
return PartialView(semester);
}
//
// POST: /Semester/Create
[HttpPost]
public ActionResult Create(Semester semester)
{
semester.ID = Guid.NewGuid();
semester.CreatedDate = DateTime.Now;
semester.CreatedBy = "ddf";
db.Semesters.AddObject(semester);
db.SaveChanges();
return RedirectToAction("Index", "Student");
}
I do get all the result of the student at get Method but all the student data are Lost at the post method.
Help!

The object passed to POST action is not the same as object passed to the view in GET action. In your POST action you get Semester instance created by MVC using only parameters Request (query string, post data) - that means Student instance is long gone. You will need to pass student ID to POST action and fill it there.
[HttpPost]
public ActionResult Create(Guid studentID, Semester semester)
{
semester.ID = Guid.NewGuid();
semester.CreatedDate = DateTime.Now;
semester.CreatedBy = "ddf";
semester.Student = db.Students.Single(s => s.ID == StudentID);
db.Semesters.AddObject(semester);
db.SaveChanges();
return RedirectToAction("Index", "Student");
}

Related

.Net MVC verify only one checkox checked

I have a model called Employee with a boolean field called OnDuty. Our business rules only allow for one employee on duty.
On the index page, I've setup the checkbox so they trigger an update call to update the employee as being "on call". However, I'm not set any other employees to off duty using my controller action below. How do I go about making sure that no other employee is on duty?
[HttpPost]
public JsonResult Update(Employee employee)
{
IEnumerable<Employee> onCallEmployee = _db.Employees.Where(e => e.OnCall == true);
foreach (Employee e in onCallEmployee) {
e.OnCall = false;
_db.Entry(e).State = EntityState.Modified;
_db.SaveChanges();
}
_db.Entry(employee).State = EntityState.Modified;
_db.SaveChanges();
return Json("Employee updated!");
}
It appears that my error(s) were caused by the way I was trying to update the employees. I had to exclude the employee which was already being updated by the function from onCallEmployee because it would throw an error (Attaching an entity of type 'Employee' failed because another entity of the same type already has the same primary key value.) when trying to save the updates.
Also, based on #mwwallace8, suggestion, I removed the SaveChanges() call from the for loop and left a single call at the end.
[HttpPost]
public JsonResult Update(Employee employee)
{
IEnumerable<Employee> onCallEmployee = _db.Employees.Where(e => e.OnCall == true && e.ID != employee.ID);
foreach (Employee e in onCallEmployee) {
e.OnCall = false;
_db.Entry(e).State = EntityState.Modified;
}
_db.Entry(employee).State = EntityState.Modified;
_db.SaveChanges();
return Json("Employee updated!");
}

update single value in EF 4.0

i m working on MVC application and using Entity Framework 4.0 for database connection.While editing record i want to update some fields in table. code for edit is
[HttpPost]
public ActionResult Edit(ProjectActivityDetail projectactivitydetail, FormCollection formcollection)
{
if (ModelState.IsValid)
{
string value = Request["ChkIntBool"];
if (value.Substring(0, 4) == "true") { projectactivitydetail.IsApproved = 1; } else { projectactivitydetail.IsApproved = 0; }
projectactivitydetail.ProjectActivityDID = long.Parse(Session["ProjectActivityDID"].ToString());
projectactivitydetail.UpatedBy = long.Parse(Session["UserID"].ToString());
projectactivitydetail.UpdatedON = System.DateTime.Now;
db.Entry(projectactivitydetail).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.FK_ProjectActivityID = new SelectList(db.ProjectActivityMasters, "ProjectActivityID", "ActivityName", projectactivitydetail.FK_ProjectActivityID);
return View(projectactivitydetail);
}
i just want to update these fields but when this executred my other fields updated to null , is there any way i can keep those values as it is and update these many values in database table.please help
It looks like the entity being passed into the service call is not complete. My advice would be to find the existing entity and make the changes to that rather than attaching the one passed in:
[HttpPost]
public ActionResult Edit(ProjectActivityDetail projectactivitydetail, FormCollection formcollection)
{
if (ModelState.IsValid)
{
//I'm assuming the PK of the entity is id so adjust for that
var entity = db.Set<ProjectActivityDetail>().Find(projectactivitydetail.id);
string value = Request["ChkIntBool"];
entity.IsApproved = value.Substring(0, 4) == "true" ? 1 : 0;
entity.ProjectActivityDID = long.Parse(Session["ProjectActivityDID"].ToString());
entity.UpatedBy = long.Parse(Session["UserID"].ToString());
entity.UpdatedON = System.DateTime.Now;
db.Entry(entity).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.FK_ProjectActivityID = new SelectList(db.ProjectActivityMasters, "ProjectActivityID", "ActivityName", projectactivitydetail.FK_ProjectActivityID);
return View(projectactivitydetail);
}
Yes, there's a way. Add hidden fields to your view with the data you want to persist on the model, int this case ProjectActivityDetail, this way the properties will get bound to the projectactivitydetail variable on the model binding stage.
Suppose you have a property called CreatedOn that is being set to null, on your view you'd add:
#Html.HiddenFor(model => model.CreatedOn)
Then, when you submit the form the value originally on CreatedOn will be bound to the property at projectactivitydetail and your model will be saved just fine. Your fields are being updated to null because model binding is not finding any values for them.
Good luck.

ASP.net MVC 3 customizing Html.ValidationMessageFor based on model logic

I've been reading over several of the questions similar to this, dealing with customizing the #Html.ValidationMessageFor but none of them touched on what I'm looking to do.
The current form I'm working on is editing a user in a database. Within this form I need to check that the email being entered is not already used for another user. I have the logic, but what I don't have is the custom validation message to appear on the page if they use an already in-use email.
Controller code:
[HttpPost]
public ActionResult EditUser(int id, EditUserModel model)
{
if (ModelState.IsValid)
{
tbl_Users editedUser = tblUsers.EditUser(id, model, HttpContext.User.Identity.Name);
tblHSDA.EditHSDAS(id, editedUser, model.hsdas, HttpContext.User.Identity.Name);
return Redirect("~/UserManage/ListActiveUsers");
}
if (tblUsers.ValidateEmailInUse(model.Email))
{
// change validation message and return View(model);
}
tbl_Users tbl_users = db.tbl_Users.SingleOrDefault(item => item.User_id == id);
ViewBag.hsdas = tblHSDA.GetHSDANameAlpha();
ViewBag.Username = tbl_users.Username;
return View(model);
}
Is this something done at the Controller level?
as per your logic the email check part will never execute if the user fills in the form correctly and provides a duplicate email
what you can do is change the ActionResult like
[HttpPost]
public ActionResult EditUser(int id, EditUserModel model)
{
if (ModelState.IsValid)
{
if(!CheckEmail(model.Email)){
tbl_Users editedUser = tblUsers.EditUser(id, model, HttpContext.User.Identity.Name);
tblHSDA.EditHSDAS(id, editedUser, model.hsdas, HttpContext.User.Identity.Name);
return Redirect("~/UserManage/ListActiveUsers");
}else{
ModelState.AddModelError("Email","Email provided is already in use...")
}
}
tbl_Users tbl_users = db.tbl_Users.SingleOrDefault(item => item.User_id == id);
ViewBag.hsdas = tblHSDA.GetHSDANameAlpha();
ViewBag.Username = tbl_users.Username;
return View(model);
}
private bool CheckEmail(string email){
//email check logic
// return true or false
}
also have a look at http://msdn.microsoft.com/en-us/library/gg508808%28v=vs.98%29.aspx

RedirectToAction after validation errors

If I have the usual Edit actions, one for GET to retrieve an object by it's ID and to display it in an edit form. The next for POST to take the values in the ViewModel and update the object in the database.
public virtual ActionResult Edit(int id)
[HttpPost]
public ActionResult Edit(VehicleVariantEditSaveViewModel viewModel)
If an error occurs during model binding in the POST action, I understand I can RedirectToAction back to the GET action and preserve the ModelState validation errors by copying it to TempData and retrieving it after the redirect in the GET action.
if (TempData["ViewData"] != null)
{
ViewData = (ViewDataDictionary)TempData["ViewData"];
}
How do I then convert that ViewData, which includes the previous invalid ModelState, into a new model to send to the view so the user sees their invalid input with validation warnings? Oddly enough if I pass in a new instance of my ViewModel retrieved from the database (with the original valid data) to the View() this is ignored and the (invalid) data in the ViewData is displayed!
Thanks
I had a similar problem and decided to use the following pattern:
public ActionResult PersonalRecord(Guid id)
{
if (TempData["Model"] == null)
{
var personalRecord = _context.PersonalRecords.Single(p => p.UserId == id);
var model = personalRecord.ToPersonalRecordModel();
return View(model);
}
else
{
ViewData = (ViewDataDictionary) TempData["ViewData"];
return View(TempData["Model"]);
}
}
[HttpPost]
public ActionResult PersonalRecord(PersonalRecordModel model)
{
try
{
if (ModelState.IsValid)
{
var personalRecord = _context.PersonalRecords.Single(u => u.UserId == model.UserId);
personalRecord.Email = model.Email;
personalRecord.DOB = model.DOB;
personalRecord.PrimaryPhone = model.PrimaryPhone;
_context.Update(personalRecord);
_context.SaveChanges();
return RedirectToAction("PersonalRecord");
}
}
catch (DbEntityValidationException ex)
{
var errors = ex.EntityValidationErrors.First();
foreach (var propertyError in errors.ValidationErrors)
{
ModelState.AddModelError(propertyError.PropertyName, propertyError.ErrorMessage);
}
}
TempData["Model"] = model;
TempData["ViewData"] = ViewData;
return RedirectToAction("PersonalRecord", new { id = model.UserId });
}
Hope this helps.
I noticed that the Model is included in ViewData so you don't need to pass it in addition to the ViewData, what I don't understand is how you get at it to then return it to the view.
public ViewResult Edit(int id)
{
// Check if we have ViewData in the session from a previous attempt which failed validation
if (TempData["ViewData"] != null)
{
ViewData = (ViewDataDictionary)TempData["ViewData"];
}
VehicleVariantEditViewModel viewModel = new VehicleVariantControllerViewModelBuilder()
.BuildForEdit(id);
return View(viewModel);
}
The above works but obviously it's making an unnecessary call to the database to build a new Model (which gets automagically overwritten with the invalid values from the Model in the passed ViewData)
Confusing.

MVC Delete record but how to code this in Controller

I'm a beginner of MVC3 with ASP.Net (C#) but I don't get the next situation to delete a record.
I have a View that ask the user to confirm delete a item (record). As code I have this to initialize the view:
public ActionResult KeywordsDelete(Guid id)
{
_db = new BlaContext();
return _db.SearchTerms.Where(x => x.id.Equals(id)).First();
}
But when confirmed, then I have the next code.
[HttpPost]
public ActionResult KeywordsDelete(Guid id)
{
_db = new BlaContext();
var term = _db.SearchTerms.Where(x => x.id == id).First();
_db.SearchTerms.Remove(term);
_db.SaveChanges();
return View("Keywords", _db.SearchTerms.ToList());
}
Building is not possible because the signature of this method is already exists (same parameters and method name).
So I don't get how to delete a record in this situation. The view is created with a default Scaffold template (delete).
I found an alternative solution to this problem while reading up on MVC. Check out: Improving the Details and Delete Methods
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id = 0)
{
// Delete stuff...
}
This will route the action Delete to the method DeleteConfirmed.
You can give your post function another additional parameter
[HttpPost]
public ActionResult KeywordsDelete(Guid id, FormCollection collection)
{
_db = new BlaContext();
var term = _db.SearchTerms.Where(x => x.id == id).First();
_db.SearchTerms.Remove(term);
_db.SaveChanges();
return View("Keywords", _db.SearchTerms.ToList());
}
But your GET Action should also return a View not a data object, I think.
public ActionResult KeywordsDelete(Guid id)
{
_db = new BlaContext();
return View(_db.SearchTerms.Where(x => x.id.Equals(id)).First());
}

Resources