I want to delete the data. here is my code. when i trying to delete the data it gives an error.
this is my code
public ActionResult delete(Int32 id)
{
var contentdelete = (from m in _db.tb_content
where m.id == id
select m).First();
return View(contentdelete);
}
public ActionResult delete(MvcNTL.Models.tb_content contentdelete)
{
var content = (from m in _db.tb_content
where m.id == contentdelete.id
select m).First();
if (!ModelState.IsValid)
return View(content);
_db.ApplyCurrentValues(content.EntityKey.EntitySetName, contentdelete);
_db.SaveChanges();
return RedirectToAction("index");
}
this is the error
The current request for action 'delete' on controller type 'ContentController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult delete(Int32) on type MvcNTL.Controllers.ContentController
System.Web.Mvc.ActionResult delete(MvcNTL.Models.tb_content) on type MvcNTL.Controllers.ContentController
You need to add [HTTPPOST] At your second delete controller. They both are get controllers now, so mvc doesn't know which one to pick.
You cannot have 2 actions with the same name on the same controller accessible with the same HTTP verb. You should decorate the second one with the [HttpPost] attribute:
[HttpPost]
public ActionResult delete(MvcNTL.Models.tb_content contentdelete)
{
var content = (from m in _db.tb_content
where m.id == contentdelete.id
select m).First();
if (!ModelState.IsValid)
return View(content);
_db.ApplyCurrentValues(content.EntityKey.EntitySetName, contentdelete);
_db.SaveChanges();
return RedirectToAction("index");
}
This makes the second action that is actually performing the delete accessible only with the POST verb. The first action will be accessible with the GET verb and would render the form.
[HttpPost]
public ActionResult delete(MvcNTL.Models.tb_content contentdelete)
{
var content = (from m in _db.tb_content
where m.id == contentdelete.id
select m).First();
if (!ModelState.IsValid)
return View(content);
_db.ApplyCurrentValues(content.EntityKey.EntitySetName, contentdelete);
_db.SaveChanges();
return RedirectToAction("index");
}
Related
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!");
}
i have the following model method inside my asp.net MVc web application:-
public IQueryable<User> searchusers(string q, int id)
{
return from u in entities1.Users
where (!u.Users_Classes.Any(c => c.ClassID == id) && (u.UserID.Contains(q))
select u;
}
which will be called using the following action method:-
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Search(string q, int classid)
{
var users = r.searchusers(q, classid).ToList();
ViewBag.id = classid;
// code does here
}
now if i remove the .ToList() from my action method the code will still work fine,, so will using the .ToList() method bring any advantages or features ?
BR
Edit:-
here is the full code for my action method:-
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Search(string q, int classid)
{
var users = r.searchusers(q, classid).ToList();
ViewBag.id = classid;
return PartialView("_usersearch", users);
}
When you call ToList, you ask the Entity Framework to execute the query immediately, and then you will work with in memory collection. Otherwise, the query will be executed when you loop through the result.
I'm trying to create a very basic MVC app based on a tutorial. I am using the default routing, and simple Views and Model.
The problem I am having is with the HttpPost Edit function. I am expecting an object of my "MyObject" type to be passed as the parameter, but it always comes back null.
Here are my Edit functions from the controller (the Get function works properly):
public ActionResult Edit(int? id)
{
if (!id.HasValue)
return RedirectToAction("Index");
var item = (from obj in mDB.MyDatabaseObjects
where obj.Id == id
select obj).First();
return View(item);
}
//
// POST: /Main/Edit/5
[HttpPost]
public ActionResult Edit(MyDatabaseObject someObject)
{
var original = (from obj in mDB.MyDatabaseObjects
where obj.Id == someObject.Id
select obj).First();
if (!ModelState.IsValid)
return View(original);
mDB.ApplyCurrentValues(original.EntityKey.EntitySetName, someObject);
mDB.SaveChanges();
return RedirectToAction("Index");
}
Note that my (nearly identical) Create method works as expected:
[HttpPost]
public ActionResult Create([Bind(Exclude="Id")] MyDatabaseObject newObject)
{
if (!ModelState.IsValid)
return View();
int max = mDB.MyDatabaseObjects.Max(data => data.TaskOrder);
newObject.TaskOrder = max + 1;
mDB.AddToMyDatabaseObjects(newObject);
mDB.SaveChanges();
return RedirectToAction("Index");
}
Thanks,
wTs
Ensure the values on your view for MyDatabaseObject are inside of the form. Validate these values are being posted over - inspect Request.Form or use change the method signature to use
FormsCollection collection
simply to validate the values are getting posted. If its choosing that method - it should be matching the properties to the form field - its generally very simple.
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.
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());
}