I'm developing my first Spring 3 webapp. In Spring 2, we used to have formBackingObject load data from the database, then let Spring binding update some of the fields, and then onSubmit would persist those changes.
In Spring 3 it seems I have two options:
Let the user edit 100% of the persistent object. This would mean that the object's ID would need to be a hidden field
Create a form object which holds the editable data, and then map that onto the persistent object on submit
The first option is not truly an option, we cannot let the user edit all fields, and we'd rather not present data in hidden fields where anyone capable of pressing F12 can alter the values.
The second option seems like a decent design approach. However, it appears that it requires to essentially clone every editable, persistent class.
#Entity
public class Company {
private String uuid; // not editable!
.. 30 other properties, 2 are not editable
}
public class CompanyForm {
.. 28 of above properties
}
and then some mapping mechanism with lots of
public void map(CompanyForm cf, Company c) {
cf.setName(c.getName());
.. 27 other set(get())
}
I'm praying this is not the "as designed" approach of Spring's MVC binding. However, all tutorial I've found so far are terribly trivial and implement option 1 from above. Does anyone have some suggestions for implementing option 2?
Thanks, Simon
DataBinder API
Note that there are potential security implications in failing to set an array of allowed fields. In the case of HTTP form POST data for example, malicious clients can attempt to subvert an application by supplying values for fields or properties that do not exist on the form. In some cases this could lead to illegal data being set on command objects or their nested objects. For this reason, it is highly recommended to specify the allowedFields property on the DataBinder.
You can use it together with option 1
A pragmatic way would be to just ignore the non editable fields on the update statement.
I have actually circumvented this in the past by using a #ModelAttribute annotation and detecting the PK on the request, if you do it this way Spring will use the object that is returned from #ModelAttribute and automatically copy the submitted object to it.
It's kind of a hack and not obvious to someone who comes in to maintain the code though.
Related
I have a #OneToMany JPA association with an instance of Curriculum having several instances of WorkExperience.
The issue I have is that I want to be able to persist one Curriculum together with several WorkExperiences in a single entity manager persist/save call.
I am not sure how to glue several instances of WorkExperiences coming from a regular HTTP POST of a html form to a java collection/set in the Spring MVC model attribute...
First of all, is this possible at all? If so is it a good idea and what kind of html can post collections/arrays of data in a regular HTTP POST?
The Curriculum JPA entity:
#Entity
public class Curriculum {
...
#OneToMany
private Set<WorkExperience> workExperiences;
...
The WorkExperience JPA entity:
#Entity
public class WorkExperience {
...
Yes, it is possible. Spring MVC supports sending Lists/Maps as form values. The way that works is by subscripting the value. For a List, you use the list number, like
<form:input path="myVal[1].property" />
And for a Map you use the map key like
<form:input path="myVal[key].property' />
This is assumming your Model Attribute has a List/Map of said item. I would recommend using a DTO and translating to your Entity. It may be overkill, but I have a problem with allowing the View to manipulate my Entity objects directly.
Also to note: You will have to do some View-side coding to dynamically add/remove items on the form. This can be a real pain, as deletes don't work like you would imagine. Spring MVC has the ability to add to a List/Map, alter the items in a List/Map, but I haven't found a way to remove items from a map directly. I usually handle removes by adding a "remove" boolean flag into my DTOs, then tracking removals by simply adding a form:hidden element for that item in the List/Map, and clean the List/Map on the server-side when I get it.
Once you get all your Entities on the Server-side, then you have to store them. If you want this to be more auto-magic, simply set an annotaion on your parent Entity like
#OneToMany(cascade=CascadeType.PERSIST)
There are several CascadeTypes available, so pick the one that makes sense.
I've been at this same question in different forms now for a while (see e.g. Entity Framework and MVC 3: The relationship could not be changed because one or more of the foreign-key properties is non-nullable ), and it's still bugging me, so I thought I'd put it a little more generically:
I feel this can't be a very unusual problem:
You have an entity object (using Entity Framework), say User. The User has some simple properties such as FirstName, LastName, etc. But it also has some object property lists, take the proverbial example Emails, to make this simple. Email is often designed as a list of objects so that you can add to that object properties like Address and Type (Home, Work, etc). I'm using this as an example to keep it generic, but it could be anything, the point is, you want the user to be able to add an arbitrary number of these items. You should also be able to delete items (old address, or whatever).
Now, in a normal web page you would expect to be able to add these items in the same View. But MVC as it seems designed only makes it easy to do this if you call up an entirely new View just to add the address. (In the template for an Index View you get the "Create New" link e.g.).
I've come across a couple of examples that do something close to what I mean here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
and
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
The problem is, although the sample projects on these sites work fine, with mock model objects, and simply lists (not an object with a child list), it's a different thing if you actually want to do something with the posted information - in my case save to database through the Entity Framework model. To adapt these cases to that, all of a sudden I'm in a maze of intricate and definitely not DRY code... Juggling objects with AutoMapper and whatnot, and the Entity Framework won't let you save and so on (see above link if you're interested in the details).
What I want to get at is, is it really possible that this is such an uncommon thing to want to do? Update a child collection in the same View as the parent object (such as the email addresses in this case)? It seems to me it can't be uncommon at all, and there must be a standard way of handling this sort of scenario, and I'm just missing it (and no one here so far has been able to point me to a straighforward solution, perhaps because I made it too abstract with my own application examples).
So if there is a simple solution to what should in my view be a simple problem (since the design is so common), please tell me.
Have you tried updating the project at your link to Steven Anderson's blog to bind to a complex object? Create a class in models called Sack and give it a single property and see if you can get it to work.
public class Sack
{
public IEnumberable<Gift> Gifts { get; set; }
}
It only took me a minute to get it up and running as I think you intend. The improvement I would have made next would be to add an HtmlHelper extension that is essentially the same as Html.EditorFor(m => m.SomeProperty), only call it something more meaningful and have it interface with the prefix scope extensions provided in the project.
public static class HtmlExtensions
{
public static IHtmlString CollectionEditorFor<TModel, TValue>(this HtmlHelper html, Expression<Func<TModel, TValue>> expression)
{
if (/* type of expression value is not a collection */) throw new FailureToFollowTheRulesException("id10t");
// your implementation
}
}
I have a requirement to keep a history of values of some fields in an EF4 ASP.NET MVC3 application. This just needs to be a log file of sorts, log the user, datetime, tablename, fieldname, oldvalue, newvalue.
Although it would be pretty easy to code this in various save routines, I'm wondering if I can get global coverage by wiring it into some sort of dataannotation, so that I can perhaps declare
[KeepHistory()]
public string Surname { get; set; }
in my partial class (I'm using POCO but generated from a T4 template).
So Questions
1) Is this a bad idea ? I'm basically proposing to side-effect changes to an entity, not directly referenced by the code, as a result of an annotation.
2) Can it be done ? Will I have access to the right context to tie up with my unit of work so that changes get saved or dropped with the context save?
3) Is there a better way?
4) If you suggest I do this, any pointers would be appreciated - everything I've read is for validation, which may not be the best starting point.
Actually, validation might be a good starting point. Since an attribute does not know about which property or class it was assigned to, but a validation-attribute gets called by the validation framework with all the necessary informátion. If you implement the System.ComponentModel.DataAnnotations.ValidationAttribute class you can override the IsValid(object, ValidationContext) method, which gives you the actual value of the property, the name of the property and the container.
This might take a lot of work, since you need to get to the currently logged-in user etc. I'm guessing that the .NET implementation provides some sort of caching for the specific attributes on an entity type, which would be a pain to implement by yourself.
Another way, would be to use the ObjectStateManager exposed by your EF ObjectContext, which can provide you with the ObjectStateEntry-objects for all entities of a given state. See the
ObjectStateManager.GetObjectStateEntries(EntityState) method, for more information about how to call it (and when). The ObjectStateEntry actually contains a record of the original and current-values, which can be compared to find any changes made within the lifetime of the current ObjectContext.
You might consider using the ObjectStateManager to inject your custom logging behavior, while this behavior decides based on property-attributes which change should be logged.
I have been reading about "Fat Controllers" but most of the articles out there focus on pulling the service/repository layer logic out of the controller. However, I have run into a different situation and am wondering if anyone has any ideas for improvement.
I have a controller with too many actions and am wondering how I can break this down into many controllers with fewer actions. All these actions are responsible for inserting/updating/removing objects that all belong to the same aggregate. So I'm not quiet keen in having a seperate controller for each class that belongs to this aggregate...
To give you more details, this controller is used in a tabbed page. Each tab represents a portion of the data for editing and all the domain model objects used here belong to the same aggregate.
Any advice?
Cheers,
Mosh
For all your tabs you can use one action, that have an tab parameter, that indicate what data you need to return.
The controller job is to cast this string tab into enum type variable. Then the tab will be send to the repository, and the repository job is to return data in response to the tab value.
The controller should do its job through to services: Input Validator and Mapper.
The mapper service job is to map the user input (typically strings) into actual typed value (int, System.DateTime, enum types, etc).
The validator job is to check that the input is valid.
Following this principles should keep your controllers really tiny.
If you wanted something simple and easy I'd suggest just splitting up the controller into partial classes based on the tabs. Of course, it's still a fat controller there's just some obvious separation between the various tab functionalities.
I'm writing an ASP.NET MVC application using NHibernate as my ORM. I'm struggling a bit with the design though, and would like some input.
So, my question is where do I put my business/validation logic (e.g., email address requires #, password >= 8 characters, etc...)?
So, which makes the most sense:
Put it on the domain objects themselves, probably in the property setters?
Introduce a service layer above my domain layer and have validators for each domain object in there?
Maintain two sets of domain objects. One dumb set for NHibernate, and another smart set for the business logic (and some sort of adapting layer in between them).
I guess my main concern with putting all the validation on the domain objects used by NHibernate. It seems inefficient to have unnecessary validation checks every time I pull objects out of the database. To be clear, I think this is a real concern since this application will be very demanding (think millions of rows in some tables).
Update:
I removed a line with incorrect information regarding NHibernate.
To clear up a couple of misconceptions:
a) NHib does not require you to map onto properties. Using access strategies you can easily map onto fields. You can also define your own custom strategy if you prefer to use something other than properties or fields.
b) If you do map onto properties, getters and setters do not need to be public. They can be protected or even private.
Having said that, I totally agree that domain object validation makes no sense when you are retrieving an entity from the database. As a result of this, I would go with services that validate data when the user attempts to update an entity.
My current project is exactly the same as yours. Using MVC for the front end and NHibernate for persistence. Currently, my validation is at a service layer(your option 2). But while I am doing the coding I am having feelings that my code is not as clean as I wish. For example
public class EntityService
{
public void SaveEntity(Entity entity)
{
if( entity.Propter1 == something )
{
throw new InvalidDataException();
}
if( entity.Propter2 == somethingElse )
{
throw new InvalidDataException();
}
...
}
}
This makes me feel that the EntityService is a "God Class". It knows way too much about Entity class and I don't like it. To me, it's feels much better to let the Entity classes to worry about themselves. But I also understand your concern of the NHibernate performance issue. So, my suggestion is to implement the validation logic in Setters and use field for NHibernate mapping.