Bind Exclude Asp.net MVC doesn't work on LINQ Entity - asp.net-mvc

I'm currenty manage to get some time to work on ASP.NET MVC. I'm doing the
tutorial Create a Movie Database in ASP.NET MVC, which still uses the ADO.NET Enity Model. I managed to create a List View from the LINQ Entity Model. So here is my problem.
The Bind Attribute doesn't work on my SQL Entity.
Original Code with Ado.NET
public ActionResult Create([Bind(Exclude="Id")] Movie movieToCreate)
{
if (!ModelState.IsValid)
return View();
_db.AddToMovieSet(movieToCreate);
_db.SaveChanges();
return RedirectToAction("Index");
}
My LINQ Code
public ActionResult Create([Bind(Exclude = "Id")] Movies movieToCreate)
{
if (!ModelState.IsValid)
{
return View();
}
_db_linq.Movies.InsertOnSubmit(movieToCreate);
_db_linq.SubmitChanges();
return RedirectToAction("Index");
}
But the Id Field isn't excluded. Any Ideas? Thanks!

Your ID property is probably an int and it's not a nullable type. And because of that, even though it's excluded when binding, it's got to have a value. In this case it has the default value of its type, which is zero.
Make sure you set up your database properly, having the ID field's IsIdentity property set to true and re-create your LINQ classes.

Related

MVC Model Updating

I have a Model which is a business layer class and I pass that to the view through the controller in the following manner:
public ActionResult Edit(int id)
{
var MyModel = MyDatabaseInstance.Listings.GetByID(id);
return View(MyModel);
}
In the control for the update I have the following:
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
try
{
// TODO: Add update logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
What I really want is to be able to get back the model object that I have used during the initial binding. Is that possible? If I change the arguments of the edit as such:
public ActionResult Edit(Listing MyModel)
it complains that there is "No parameterless constructor defined for this object." and my model cannot have a parameterless constructor.
I would suggest that you use a ViewModel rather than binding directly to the entity from your database.
Using a ViewModel has the following advantages (not exhaustive).
Views often have specific requirements to how you display data. If you use the model from your DB then your going to endup adding unnecessary properties to your model.
Security, you don't want to expose properties on your model to automatic binding when posting back to the controller.
Validation requirements may be different for your view than your entity model.
Just easier to change a ViewModel if your presentation requirements change.

SaveChanges() not saving data

I'm fairly new to MVC so please be patient. Here's my action code in my controller in an MVC project I'm working on:
[HttpPost]
public ActionResult Create(User usr , string submitBtn, FormCollection form, int id)
{
var db = new UsrSqlEntities();
foreach (string fm in form)
{
if (fm.Contains("PayMonthOne"))
usr.fName = Int32.Parse(form[fm]);
}
db.SaveChanges();
}
I've debugged this in VS2010 and each step passes through with no errors i.e. 'User' exists in my Entity Framework, my 'form' contains a value which passes to 'fName'. However, running SQlProfiler in SSMS 2008 doesn't show any activity (and obviously not record in my database). My entity framework is modeled on this db as, when I do an update to an entity, the changes in the db reflect in the EF.
I don't know why SaveChanges() isn't working. Can somebody help?
If you are updating the entity, you will need to connect the usr object to the db context and mark it as modified.
db.Attach(usr);
db.Context.Entry(usr).State = EntityState.Modified;
If it is new you will need to add it via:
db.Add(usr);
Then call your
db.SaveChanges()
I would recommend the following:
var db=new UsrSqlEntities(); /* Module Level declaration */
[HttpPost]
public ActionResult Create(User usr)
{
db.Users.Add(usr); /* Add usr object to Users DbSet */
db.SaveChanges(); /* Save all changes to the database */
}
This assumes that you are creating a new User, and Users is your DbSet for User objects, and your User object has a property "PayMonthOne" of type int or int?.

How do I scaffold when creating a Controller that represents more than 1 Entity?

I have Entity Framework modeling a legacy database that has about 30 tables. I am using ASP.NET MVC 4 and would love to use scaffolding based on an Entity in my EDM. I have seen a ton of examples on this but I am running into an issue. My needs are not so cookie cutter as the examples I have seen which are like this: create a Controller that scaffolds a 'Customer' entity, and upon saving changes the Controller action takes in a Customer as it's parameter and using model binding all is well after the following is done:
[HttpPost]
public ActionResult Create(Customer customer)
{
if (ModelState.IsValid)
{
db.Customers.AddObject(customer);
db.SaveChanges();
return RedirectToAction("Index");
}
}
Perfect and pretty right; well this does not work for me. In my situation my screen needs fields from about 6 different entities and updates back to those same 6 entities.
So a 2 part question:
How do I even scaffold my controller and resulting view(s) when it is not a simple 1 entity to 1 screen deal like the simple example from above?
Will I still be able to use model binding to persist changes back to my entities since once again the resulting view will be a result of about 6 different entities, and without a lot of manual updating of properties on each individual entity?
If I am totally off base please guide me back. I want to know exactly how I accomplish this task as it will happen repeatedly throughout my MVC application and I need to know how to still use scaffolding and model binding when possible.
Thanks!
When you run into a scenario like this, it's time to start considering using ViewModels and EditModels, which are models dedicated to showing the exact properties needed by the View.
One strategy for doing this:
Create new folders in your project: ViewModels and EditModels.
For each details view, add a ViewModel class, and for each edit/create view, add an EditModel class.
In your controller, map from your entities to your ViewModel/EditModel when the page is first requested. On postbacks, perform validation and map from you EditModel back to your entities.
A few notes:
This does add some work, but it's really the only solid way to take advantage of the strongly-typed view capability of MVC.
To minimize the tedium of going from entities to ViewModels, you can use something like AutoMapper to automatically map between properties with the same name (and set up rules for the remaining mappings).
Some manual work will likely be needed to go from EditModels back to entities. AutoMapper can handle some scenarios, but it's probably not the ideal tool for that type of mapping (it works much better for going from an entity to a ViewModel). I have heard of people using the command pattern and rules engines for performing the mapping back to entities, but thus far, a truly detailed explanation or tutorial for these techniques has evaded me.
ViewModel example (from the NerdDinner tutorial)
public class DinnerFormViewModel {
// Properties
public Dinner Dinner { get; private set; }
public SelectList Countries { get; private set; }
// Constructor
public DinnerFormViewModel(Dinner dinner) {
Dinner = dinner;
Countries = new SelectList(PhoneValidator.AllCountries, dinner.Country);
}
}
// controller actions
[Authorize]
public ActionResult Edit(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
return View(new DinnerFormViewModel(dinner));
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection collection) {
Dinner dinner = dinnerRepository.GetDinner(id);
try {
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id=dinner.DinnerID });
}
catch {
ModelState.AddModelErrors(dinner.GetRuleViolations());
return View(new DinnerFormViewModel(dinner));
}
}
Source: http://nerddinnerbook.s3.amazonaws.com/Part6.htm

What is FormCollection argument for? Is it a dummy argument?

Up to now I have no idea why does VS provide FormCollection argument by default?
public ActionResult Edit(int id)
{
Dinner dinner = dinnerRepository.GetDinnerById(id);
if (dinner == null)
return View("NotFound");
else
return View(dinner);
}
[HttpPost]
public ActionResult Edit(int id, object dummy/*, FormCollection collection*/)
{
Dinner temp = dinnerRepository.GetDinnerById(id);
if (TryUpdateModel(temp))
{
dinnerRepository.Save();
return RedirectToAction("Details", new { id = temp.DinnerId });
}
else
return View(temp);
}
EDIT 1: In my experiment, any arguments other than id are dummy because they never be used in httppost Edit action method.
EDIT 2: Does TryUpdateModel use FormCollection behind the scene?
If your app receives a POST, then 99.99% of the time it will come from an HTML form. The FormsCollection gathers all the values in the form for you.
In ASP.NET MVC you are almost always better off using strongly typed objects though. The DefaultModelBinder will create them for you most of the time, and you can implement IModelBinder if needed if the default one doesn't do what you need.
The FormCollection is how ASP.NET provides you access to the values that were just posted to your page.
You could also use a strongly typed argument and then ASP.NET MVC would use the FormCollection internally to create your strongly typed object.
FormCollection contains your form state coming back to your server.
If you need any custom operation on the processing of your data you use FormCollection. Otherwise you can happily remove it.
I am using it heavily for a hierarchical model processing.

Preventing EF4 ConstraintException when invoking TryUpdateModel

Given following ASP.NET MVC controller code:
[HttpPost]
public ActionResult Create(FormCollection collection)
{
string[] whitelist = new []{ "CompanyName", "Address1", "Address2", ... };
Partner newPartner = new Partner();
if (TryUpdateModel(newPartner, whitelist, collection))
{
var db = new mainEntities();
db.Partners.AddObject(newPartner);
db.SaveChanges();
return RedirectToAction("Details/" + newPartner.ID);
}
else
{
return View();
}
}
The problem is with the Entity Framework 4: the example Partner entity is mapped to a database table with it's fields NOT ALLOWED to be NULL (which is ok by design - they're required).
Unfortunately, invoking TryUpdateModel when some of the properties are nulls produces as many ConstraintExceptions what is not expected! I do expect that TryUpdateModel return false in this case.
It is ok that EF wouldn't allow setting a property's value to null if it should not be, but the TryUpdateMethod should handle that, and add the error to ModelState errors collection.
I am wrong, or somebody screwed up the implementation of TryUpdateModel method?
It's not "screwed up". It's by design. My preferred way of dealing with this is to bind to an edit model rather than directly to an entity. If that's not an option for you, then you can write an associated metadata provider or initialize the properties.

Resources