I'm using MVC 2 with EF4. Creating or deleting objects works but update doesn't.
I have read lot and lot tutorials / questions on StackOverflow, but I haven't found a real WORKING code to use in my "Edit" method.
[HttpPost]
public ActionResult Edit(int id, Account model)
{
try
{
Account accountEdited = accountRepository.Get(id);
// Working code to update "accountEdited" with "model"'s values ???
accountRepository.Save();
return RedirectToAction("Details", new { id = id });
}
catch (Exception ex)
{
return View();
}
}
I'm using EntityFramework with WCF Data Service
This is what I do:
[HttpPost]
public ActionResult Edit(int id, Account model)
{
try
{
Account accountEdited = accountRepository.Get(id);
TryUpdateModel(accountEdited);
ctx.SaveChanges();
return RedirectToAction("Details", new { id = id });
}
catch (Exception ex)
{
return View();
}
}
The initial call to the repository will ensure the entity is in the graph, in an Unmodified state. MVC's built in TryUpdateModel method will then merge the two objects together (the accountEdited object, and the form post data that has been model bound).
This will result in the entity being in a Modified state.
Simply calling SaveChanges() on the object context will then push the changes to the database.
I have dabbled in techniques such as the "stub technique" but it introduced a world of pain (mainly to do with relationships), so this is the easiest approach, and works well.
You have your real EF work abstracted from you code you posted. Here is the simplest EF save:
public void Save(Account account)
{
using (DBContext ctx= new DBContext ())
{
ctx.Attach(account);
ctx.SaveChanges();
}
}
You only need to attach the object if it was obtained in another context. If not you can do it like:
public void Save(int AccountID)
{
using (DBContext ctx= new DBContext ())
{
Account account = ctx.Account.Single(a => a.ID == AccountID)
account.property = somepropchange;
ctx.SaveChanges();
}
}
Related
I'm quite new to ASP.NET and MVC and I get confused about the CRUD logic. I found the following explanation from a resource, however, as far as I know, the CRUD are performed in controller, for instance, they are achieved by the actions such as Index, Create, DeleteConfirm, Edit, etc. Am I misunderstanding this concept?
According to the picture above, the model is the "Doamin Model", it is not "M" from MVC as Slava Utesinov said, it's a concept of DDD(Domain-Driven Design).
In ASP.NET MVC, the traditional way that where we do CRUDs are in actions of controllers, and your understand is right.
In DDD concept(Domain-Driven Design), we do CRUDs in domain model.
Whatever we use DDD architecture or traditional ways, we need to do that based on the basic MVC architecture.
More information about DDD for your reference:
Domain-Driven Design – What is it and how do you use it?
Yes you are right, CRUD operations can perform in Controller by actions and Model can help to achieve that. Model is nothing but a class which will having properties in that.
For example: "Employee" is class which is having different properties like "FirstName, LastName, EmployeeID, Email, DateOfJoining etc.". Now if you have to perform CRUD operation on this then you have to write code in Controller Class under different actions by using this "Employee" model class.
Model only cannot perform CRUD operation.
You can do it wherever you want it but you will be breaking the concept which is "Separation of Concerns". The Controller should only be concern of which view or which action it is going to call or perform. The Model should only be used how your data is going to be structured, it is usually similar to how your database properties look. In short, your Model (class model) should have minimal thinking. For example, you have a table called Person with columns as IDPerson, FirstName,LastName. Your model should be something similar to this:
public class Person {
public IdPerson {get;set;}
public FirstName {get;set;}
public LastName {get;set;}
}
Let's say you have a view that shows the detail of a person which could be something
like this:
public class PersonController : Controller
public ActionResult GetPerson(int IdPerson){
PersonBusinessLogic pbl = new PersonBusinessLogic();
Person p = pbl.GetPersonFromDatabase(id); //To add more consistency, the data access is on a separate class for better maintenance and to emphasize "Separation of Concerns"
ViewResult vr = new ViewResult()
{
ViewName = this.View,//This is where you assign the page if you have other pages for this action
ViewData = new ViewDataDictionary(ViewData)
{
Model = p
}
};
return vr;
}
For your crude:
[HttpPost]
public ActionResult CreatePerson(Person p)
{
try
{
if (ModelState.IsValid)
{
PersonBusinessLogic pbl = new PersonBusinessLogic();
pbl.CreatePersonToDatabase(p);
return RedirectToAction("Index", "Home");
}
}
catch(Exception ex){
ModelState.AddModelError("",ex.Message);
}
return View(p);
}
[HttpPost]
public ActionResult UpdatePerson(Person p)
{
try
{
if (ModelState.IsValid)
{
PersonBusinessLogic pbl = new PersonBusinessLogic();
pbl.UpdatePersonToDatabase(p);
return RedirectToAction("Index", "Home");
}
}
catch(Exception ex){
ModelState.AddModelError("",ex.Message);
}
return View(p);
}
[HttpPost]
public ActionResult DeletePerson(Person p)
{
try
{
if (ModelState.IsValid)
{
PersonBusinessLogic pbl = new PersonBusinessLogic();
pbl.DeletePersonByIDFromDatabase(p.IdPerson);
return RedirectToAction("Index", "Home");
}
}
catch(Exception ex){
ModelState.AddModelError("",ex.Message);
}
return View(p);
}
To give you a better idea, Find some article on how MVC is greatly applied as a concept then you will greatly appreciate the learning process.
I have close to 10 controllers that currently share the same code. The code is pretty simple, it just checks if a set of data is null and checks if the current user has permission to access the data.
If there is an issue, I throw an HttpResponseException.
The code works when it is sitting in each controller. I have also managed to centralize the code but I think the way I have done it is wrong. I've created a new class which inherits ApiController and then I have the controllers inheriting my new class. This is the only way I could get the HttpResponseExceptions working. Code is as follows:
//New centralized class:
public class AuthorizationClass : ApiController
{
private DataModel db = new DataModel();
public async Task checkUserisValid(int user_id)
{
user_list user_list = await db.user_list.FindAsync(user_id);
if (user_list == null)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest,"This user does not exist"));
}
int businessID = user_list.business_id;
var result = checkAccess(User.Identity.Name, businessID);
if (result.Count <= 0)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "You do not have access to modify this business"));
}
}
public static List<user_details> checkAccess(string userName, int id)
{
//code which checks if the user is in the right tables
return checkAccess.ToList();
}
}
Then in the controller class, I have:
public class MyController : AuthorizationClass
{
public async Task<IHttpActionResult> Postnew_table(int id, new_table new_table)
{
await checkUserisValid(id);
//rest of controller
}
}
I tried to do it in different ways but this is the only way I could get it working with HttpResponseException. Is there a better way to do this without inheriting classes or is this the only way to do what I am after?
Thanks.
You could just move these 2 methods to some static helper class in a common assembly, you mention that Request is an instance variable on the controller, just pass it to the method.
public static class SomeHelper
{
public static async Task checkUserisValid(int user_id, DataModel db, Request request, User user)
{
user_list user_list = await db.user_list.FindAsync(user_id);
if (user_list == null)
{
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.BadRequest,"This user does not exist"));
}
int businessID = user_list.business_id;
var result = checkAccess(user.Identity.Name, businessID);
if (result.Count <= 0)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "You do not have access to modify this business"));
}
}
public static List<user_details> checkAccess(string userName, int id)
{
//code which checks if the user is in the right tables
return checkAccess.ToList();
}
}
I have an asp.net mvc4 application in which i have this snippet:
public bool Logout() {
try {
session["user"] = null;
return true;
}
catch {
return false;
}
}
when i put this code in a controller it's works but if i put it in a model class it didn't.
the problem is in the session["user"] = null; .
So how can i manage the session's variables in a model class?
This functionality should not be in a view model. The model should be used for passing data from controllers to views for displaying, and receiving submitted data from views.
See a question like What is a ViewModel in MVC to get a better explanation.
A logout function should be an action on a controller. Something like:
public ActionResult Logout()
{
Session["user"] = null;
// Redirect user to homepage
return Redirect("/");
}
In class access by the current context :
HttpContext.Current.Session["user"]....
Can someone please check out this code, i really dont understand why i got violation of unique when i try to update an record. the code used to create new record work just fine, but when i try to use it to update, it called out violation.
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(User user)
{
if (ModelState.IsValid)
{
userRepository.SaveUser(user);
return RedirectToAction("List");
}
else
return View("Edit");
}
userRepo:
public void SaveUser(User user)
{
user.LAST_ACTIVITY = DateTime.Now;
if (user.USER_ID != 0)
{
usersTable.Attach(user);
usersTable.Context.Refresh(RefreshMode.KeepCurrentValues, user);
}
else
{
usersTable.InsertOnSubmit(user);
}
usersTable.Context.SubmitChanges();
}
and i got an error:
Unable to refresh the specified
object. The object no longer exists
in the database.
when i try to change the userRepo like this for testing purpose.
public void SaveUser(User user)
{
user.LAST_ACTIVITY = DateTime.Now;
usersTable.Attach(user);
usersTable.Context.Refresh(RefreshMode.KeepCurrentValues, user);
usersTable.Context.SubmitChanges();
}
Im wondering if there anyone on this board can find out if i am wrong somewhere in this problem :).
Thank you very much and wish you best regard. :)
Looks like you have conflicts to resolve even though you're telling it to "KeepCurrentValues", try this before the submit changes...
foreach(ObjectChangeConflict conflict in usersTable.Context.ChangeConflicts)
{
foreach(MemberChangeConflict memberConflict in conflict.MemberConflicts)
{
memberConflict.Resolve(RefreshMode.KeepCurrentValues);
}
}
Ignore ID on your model binding.
[Bind(Exclude= "Id")]
public ActionResult Edit(User user)
Kindness,
Dan
I am currently developing an application with the new ASP.NET MVC2 framework. Originally I started writing this application in the ASP.NET MVC1 and I'm basically just updating it to MVC2.
My problem here is, that I don't really get the concept of the FormCollection object vs. the old Typed object.
This is my current code:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
try
{
Member member = new Member();
member.FirstName = collection["FirstName"];
member.LastName = collection["LastName"];
member.Address = collection["Address"];
// ...
return RedirectToAction("Details", new { id = member.id });
}
catch
{
return View("Error");
}
}
This is the Code from the MVC1 application:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Member member)
{
try
{
memberRepository.Add(member);
memberRepository.Save();
return RedirectToAction("Details", new { id = member.id });
}
catch
{
}
return View(new MemberFormViewModel(member, memberRepository));
}
What are the benefits of switching to FormCollection in MVC2 and more importantly - how is it used properly?
You had the FormCollection object in v1 as well. But it is more preferred to use a typed object. So if you are already doing that, then continue doing so.
By using FormCollection, you wind up manually matching your post data or query string key/values into values to use in your code using string typing (resulting in stringly-typed code), when instead the built-in Model Binding can do this for you if you use form models, aka "typed objects."
I think by using the FormCollection, you would probably also lose the ability to use the handy Data Annotation (slash Validation) attributes on your model objects as well, which are designed for use with typed object model binding.
Additionally, unit testing can become much more cumbersome once you start touching your controller.Request.Form. You might find yourself having to mock and setup an HttpContextBase, and an HttpRequestBase just to have that mock request's .Form property return the NameValueCollection that you are wanting your test to see. Contrast this to letting model binding do the work for you such as:
// Arrange
var myModel = new MyModel( Property1 = "value1", Property2 = "value2");
// Act
var myResult = myController.MyActionMethod(myModel);
// Assert
// whatever you want the outcome to be
In summary, I would recommend against using FormCollection to the maximum extent possible.