The way I am doing this at the moment (which works) feels a bit hacky. When I am editing an entity I don't want the user to change key auditing fields behind, for example when the entity is initially created it automatically populates DateAdded, AddedBy, EditedBy.
To stop people editing these values I don't bind them in the include when editing:
public ActionResult Edit([Bind(Include = "Id,AccountName")] Account account)
This means I have to do this to get the original values back otherwise they get set to null
account.DateAdded = db.Accounts.Where(c => c.Id == account.Id).Select(d => d.DateAdded).FirstOrDefault();
account.AddedBy = db.Accounts.Where(c => c.Id == account.Id).Select(a => a.AddedBy).FirstOrDefault();
account.EditedBy = User.Identity.Name;
Is there a better way to fix this, the way below works but doesn't feel efficient.
The recommend approach is to use a view model containing only the proeprties you need to display/edit say
public class AccountVM
{
public int ID { get; set; }
public string Name { get; set; }
}
which then then use in the view and post back to your controller, get the data model based on the ID property and map the view model properties to you data model and save. Note the [Bind] attribute is not required.
Using view models has numerous advantages including application of view specific attributes and prevention of overposting attacks. For more information refer the answers to What is ViewModel in MVC?
Tools such as automapper make it easier to map ata between you data and view models.
Related
My project has several models, some with 1:many relationships with other models. A user has a profile page, this is split up into several partial views - each grouping/representing specific attributes of the given model.
If for example, I want to display 5 of the 10 properties of a given model in a partial view, and want to persist the properties that aren't shown to the user I'm using Html.HiddenFor like so
#Html.HiddenFor(x => x.IsInGroup)
This works for single entry properties as above. Of the 5 hidden member attributes, one of these may be a list. I understand that a list cannot be persisted using HiddenFor. I've come across the Mvc Futures package and the Html.Serialize helper extension, but I'm not totally sure how to use it and havn't been able to find much good information on it.
Once a model is passed to a view everything associated with it (properties, collections) is available for us to access e.g. Model.Username. If for example we don't use HiddenFor with Username, does that mean it will be reset to a default value, or null? Is this the same for collections?
Is using HiddenFor the only/best way to persist a model's properties that are not shown to the user?
Is using Html.Serialize the only way persist a model's collection that is not shown to the user? Other options?
Could someone provide/link to a simple example of how to persist a collection in a situation similar to what I've described?
If I was to use Html.Serialize, does the whole model need to be serialised or can I just serialise the collection?
Feedback appreciated.
You don't need to "persist" any data from your model by creating all the fields (hidden or not) from the model. In controller, when updating the record in the database you will just update what you need, the rest will not be affected.
Let's say this is your Product model
class Product {
public int ID {get; set;}
public string Name {get; set;}
public string Description {get; set;}
public decimal Price {get; set;}
public virtual ICollection<Category> Categories { get; set; }
}
If you only want to edit Name and Description in your view, then you can only put those fields, and skip the rest (the ID would be in a hidden field). When the form is submitted, in your controller you would reference the Product record by the ID that got passed in and then you can update Name and Description to what you received from the form. Categories and the price will not be affected.
Somewhat more straight forward way to do this is to use a ViewModel specific to the view without non-editable properties. I found this post that gives more details how to do this:
Successful Model Editing without a bunch of hidden fields
On a smaller project you don't have use any kind of library (AutoMapper, InjectValues, ...), but you can do it yourself in places where you need to copy the values from a ViewModel into an actual record from DB.
Application components:
NHibernate 3.3
FluentNHibernate 1.3
I'm using Automapping only at the moment (maybe that's the problem).
I'm new to NHibernate so this may be a simple question.
Here's the basic structure (not actual classes).
class Family
{
public virtual Guid ID { get; set; }
public virtual IList<Person> Members { get; set; }
}
class Person
{
public virtual Guid ID { get; set; }
public virtual Family Family { get; set; }
public virtual string Name { get; set; }
}
I have an "Edit" view for the person, that takes the ID as a parameter. The Action then loads the Person object by ID and renders the view.
The issue is when I then change something and post it back, the Person object's Family member is null, and therefore when it's save, the Person no longer has a family :(
I tried adding a "FamilyID" property, and then having that as a hidden property in the view, but there is then a problem with the NHibernate persisting it (I can post the error if that is the way this is supposed to work).
I could load the Person object when it's posted back, then just copy over some of the information but that seems wrong to me...
Any help would be greatly appreciated.
I could load the Person object when it's posted back, then just copy
over some of the information but that seems wrong to me...
If you do not have corresponding input fields for the Family properties inside your view those values will never be sent back to your controller. So you should retrieve them using the FamilyID (which you would have sent with a hidden field) from the database before updating your Person object. That's the correct flow.
UPDATE:
This being said the best way to handle this scenario is to use view models (DUH). So you will design a view model which will contain only the properties that are supposed to be edited by the user in the view. Then you will make your view strongly typed to the view model and your HttpPost controller action will take the view model as argument. Inside this action you will load the entire Person domain that needs to be updated from the database, set the properties that were modified from the view model (trivially easy with a tool such as AutoMapper) and then persist back your domain model to the database. Only the properties that were part of the view will be modified from this Person domain model.
Not sure if I'm completely missing something but, I have a typical MVC web application using EF and role based authentication, as such:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public IList<Role> UserRoles { get; set; }
}
public class Role
{
public int RoleId { get; set; }
public string Name { get; set; }
public IList<User> RoleUsers { get; set; }
}
Ideally, in the above case, I would like a single edit screen to update a users name that also allows add/delete operations on the users roles, e.g. a form with an input field for the name, a table of the users roles with each row having a delete button, and a role drop down list with an add button.
How would I perform edits on the views model (User) without persisting the role additions/deletions to the database until a save request is issued?
It may be best to think of an Add operation instead. If inserting a new user, how could you build a collection of that users roles without inserting the user first?
Thanks in advance.
After looking into this a bit more, Phil Haacked wrote an article on binding a view model to a list, found here...
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
I could probably have used this approach to have a single form with inputs for the entity properties and a collection of associated inputs bound using the above method for sub objects. Although I imagine this would probably require a duplicate list property for each navigation property on the parent entity, which is a strike for me.
If adding an entity with a collection of complex objects, this method also doesn't resolve how you might elegantly input all the properties for a complex object on the same view (as the parent entity only exists in memory) - the simplest approach probably being partial views containing the edit forms?
For simplicity, I opted to change the edit view to only edit the basic properties of the entity and have a separate link for sub objects that redirects to the relevant controller, using the User example, an add operation would follow as such:
User/Edit/{user_id} view -> Input the users name, email etc.
Click Save -> Redirect to User/Index or User/Details/{user_id}
A 'manage roles' link is available for this user, once clicked -> Redirect to /Role/Index/{user_id}
Page displays a table of roles for this user with the ability to add/edit etc.
Edit:
Also, in case this helps anyone else.
I set the /Role/Index action to list all roles by default, however it also accepts a UserId parameter (/Role/Index/{user_id}). When a UserId is specified, the action returns a different view (/Role/IndexForUser) whose data model is the User entity - it does the same as the default Index view, but only lists roles associated with the user, and displays more contextual links such as 'remove user from role'.
I am writing an application in MVC2 using Entity Framework
As I know ViewModel has to contain only data without any logic to database. Suppose I have Product class that is ADO.NET entity that has EntityCollection<ProductToStatus> when ProductToStatus is many-to-many table. I have ProductModel (that takes Product in its .ctor) which is passed to View.
public class ProductModel
{
....
public Product Item {get; private set;}
...
public ProductModel(Product item)
{
...
this.Item = item;
...
}
}
In View I need to render all statuses of the product, so to do it I need to query the DB by item.ProductToStatus.Select(s=>s.ProductStatus).ToList(); in the ProductModel, but this sends request to the DB and thus does it violates the MVC principle?
Is this OK or I need to do something?
you shouldn't do this. Your controller should collect the data required for your view and should package it up and pass it to the view for it to render.
So your ProductModel should either take the details of the Product it needs in its constructor or through properties (my preference) or should, at a push, use the Product it is given to do all the querying in the constructor to set all of its internal fields but not keep a reference to the Product around. I don't like the using the Product in the constructor particularly as its doing work in the constructor which is not great, but depending on what it is doing exactly it might be ok.
Its probably better to make your ProductModel have a load of properties, then you can create it like so:
var model = new ProductModel()
{
Statuses=product.ProductToStatus.Select(s=>s.ProductStatus).ToList(),
Name=product.Name,
OtherProperty=GetPropertyValue(product),
//etc
}
Yes its violating the pattern. You should fill your ViewModel in the Controller and then pass it to your view.
Off course it will work, but thats not the idea of model-view-controller.
I have created a repository that is returning data from my database using Entity Framework and I need to provide this data to my view, but before I do that I need to convert those objects into my domain model.
My schema looks like this:
TABLE Project
Id INT PRIMARY KEY
Name NVARCHAR(100)
TABLE Resource
Id INT PRIMARY KEY
FirstName NVARCHAR(100)
LastName NVARCHAR(100)
TABLE ProjectResources
Project_Id INT PRIMARY KEY -- links to the Project table
Resource_Id INT PRIMARY KEY -- links to the Resource table
I generated an entity model which ended up looking like this:
Project
|
---->ProjectResources
|
---->Resource
I have a repository that returns a Project:
public interface IProjectRepository
{
Project GetProject(int id);
}
And a controller action:
public ActionResult Edit(int id)
{
Project project = projectRepository.GetProject(id);
return View(project);
}
This doesn't seem to work very well when I try and POST this data. I was getting an EntityCollection already initialized error when it was trying to reconstruct the ProjectResources collection.
I think it is smarter to create a domain model that is a little simpler:
public class ProjectEdit
{
public string ProjectName { get; set; }
public List<ProjectResource> Resources { get; set; }
}
public class ProjectResource
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
This seems to be a little nicer since I also don't have the intermediate ProjectResources -> Resource jump. The ProjectResource would have the fields I need. Instead of doing something like:
#foreach( var resource in Model.ProjectResources ) {
#Html.DisplayFor(m => m.Resource.FirstName)
}
I can do:
#foreach( var resoure in Model.Resources ) {
#Html.DisplayFor(m => resource.FirstName);
}
My question is as follows
Should I be returning my domain model from my repository or should that be handled by the controller or some other class in the middle? If it's handled in the controller by something that maps my Project to a ProjectEdit, what would that look like?
My own view is that you shouldn't return anything to your controller or a view that is dependant on the implementation of your repository.
If you're using EF with the POCO Generator, it's reasonable to use those classes for your domain model because they're independent of the EF implementation (you could replace EF and retain the POCO's).
But if you're using EF with its EntityObjects, I believe you should convert to your domain model. If your Data Access was encapsulated in a WCF service which used a repository pattern internally, I wouldn't worry so much about returning EntityObjects from the Repository. But if you're using a Repository directly from MVC, use the Domain Model as the interface to the Repository.
We tend to always use a ViewModel as "the class in the middle" and map to and from the actual Model using...
Automapper
...or...
ValueInjecter
Your ViewModel can then be fairly independent of your Model in terms of structure if you want it to be.
What you describe is exactly what I've been doing for years, tying to follow n-tier application design.
Because you data will not always be organized the same way as your domain. What makes since in SQL is not always the same in your domain, as you've come across here.
Typically my domain knows what the repository looks like and has methods for converting to and from. My UI/views know what the domain looks like and have methods for retrieving that data (that goes in the controller).
So short answer, I would say, something in the middle (your business layer) and have that expose methods usable by your controllers to receive that data.