Reputation: 2799
Model
class
public class product : BaseModel
{
[key] public string id { get; set; }
[Required] public string title { get; set; }
[Required] public bool valid { set; get; }
public decimal discount { get; set; }
public string summery { get; set; }
public string icon { get; set; }
public DateTime date { get; set; }
}
in View
I just need update title
column ,
here is model code
@using (Html.BeginForm()){
@Html.HiddenFor(o => o.id);
@Html.ValidationSummary(true)
Title: @Html.EditorFor(model => model.title)
@Html.ValidationMessageFor(model => model.title)
}
in Controller
, product
lost other values except id
and title
according to this post one of the best solution is creating helper class for this specific form and use AutoMapper to map the helper to original model . but in my case ( over 60 models ) takes extra resources to implement helper classes. is there any better solution ?
Upvotes: 2
Views: 4660
Reputation: 1038880
in Controller , product lost other values except id and title
That's normal. What did you expect? Those are the only fields you have included in your HTML <form>
so those are the only things you could ever hope to get back in your controller action. That's how HTML works. Don't expect miracles, ASP.NET MVC won't just automagically set some values to the other fields of your model even if you haven't included them in the form POST.
Of course you could use the id
that you received from the request to query your datastore and retrieve the corresponding model and do the respective processing on it.
So:
[HttpPost]
public ActionResult SomeAction(int id)
{
var product = db.Products.Where(x => x.Id == id);
if (!TryUpdateModel(product))
{
// validation failed => redisplay the view
return View(model);
}
// at this stage the product variable will be updated with the title
// property coming from the view and all other properties staying untouched
// => you could persist the changes back to the database
// I don't remember the syntax of this EF stuff - go read the manual
// of how to persist the changes of this "product" instance back to the context
// As far as I remember it was something like "db.SaveChanges" or something.
...
// after a successfull UPDATE redirect in order to follow good practices of the
// Redirect-After-Post pattern: http://en.wikipedia.org/wiki/Post/Redirect/Get
return RedirectToAction("Success");
}
Be careful though with this approach though. I do not recommend it. An attacker could potentially set any properties like this by sending a specially crafted request. You should never pass your domain models to your views. You should always use view models.
In order to protect against those mass-injection attacks you should keep a list of properties that are actually allows to be updated from the view:
// ... only update the title property from the view
if (!TryUpdateModel(product, new[] { "title" }))
Now only the title
property will be updated by the default model binder.
The actual solution I recommend is to use a view model of course (I can't keep rep[eating and stressing on this fact in the gazillions of answers I provide here on StackOverflow and I still see people using those EF autogenerated domain models in their views):
So, yeah, define a view model, what does it cost you? A Ctrl+A on your Models folder and then:
public class ProductViewModel
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
}
Was it so difficult?
And then navigate to your NuGet console and type: Install-Package AutoMapper
. Then headaway to your Application_Start
in Global.asax
and define a mapping between your view model and your domain model (Actually it's better to later externalize your mapping in AutoMapper Profiles):
// gosh this EF crap generates lowercase classes => it sucks so badly
// and violates all C# conventions
Mapper.Map<ProductViewModel, product>();
and finally your controller action becomes:
[HttpPost]
public ActionResult SomeAction(ProductViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var product = db.Products.Where(x => x.Id == id);
Mapper.Map<ProductViewModel, product>(model, product);
// at this stage the product variable will be updated with the title
// property coming from the view and all other properties staying untouched
// => you could persist the changes back to the database
// I don't remember the syntax of this EF stuff - go read the manual
// of how to persist the changes of this "product" instance back to the context
// As far as I remember it was something like "db.SaveChanges" or something.
...
// after a successfull UPDATE redirect in order to follow good practices of the
// Redirect-After-Post pattern: http://en.wikipedia.org/wiki/Post/Redirect/Get
return RedirectToAction("Success");
}
Upvotes: 6