ASP.Net MVC3 Model vs ViewModel - property that I don't want written to the database
I'm currently toying with asp.net mvc3 and have a question with respect to models and viewmodels.
I have a database model that has a DateTime field. When I display this on screen I wan开发者_如何学Pythont to split the date and time portions into separate input boxes. I have thought of a few ways to accomplish this and was wondering what the best solution would be.
1) Create my model with two properties :
[DataType(DataType.Date)]
public DateTime DateOfIncident {get; set;}
[DataType(DataType.Time)]
public DateTime TimeOfIncident {get; set;}
this renders two fields on my View when I generate it. The trouble is, when this gets written to the DB, the TimeOfIncident is still rendered as a datetime in SQL Server and it defaults the date portion. To get around this, I can put some code into my controller, for example in the HttpPost Create, I can do something like:
accident.TimeCreated = (accident.DateCreated.Value.Date + accident.TimeCreated.Value.TimeOfDay);
which works (I get the TimeOfIncident with the correct date portion), but I now have two fields - DateOfIncident and TimeOfIncident, both being datetime and really, my gut says I should only have one field in the database (since it is a datetime).
2) I could create one property in my model - DateOfIncident, annotate it to be DataType.Date put add some custom "unbound" HTML into my view to capture the time. Then in my controller I could coerce that spurious element into the time portion of my DateOfIncident.
3) Create my model with only a DateOfIncident and then create a ViewModel which has looks something like:
public AccidentReport accidentReport {get; set;}
[DataType(DataType.Time)]
public DateTime TimeOfIncident {get; set;}
pass that viewmodel into my view and go from there.
I've not got much MVC experience so I'm wondering if I'm going down the right track here or if there is a better/simpler way to wire this all up?
Thanks everyone.
I think you generally want to separate out how anything is persisted into the DB from how it is displayed. Just because you've got two data entry components to describe an event (time and date) doesn't mean the underlying persistence layer should mimic that - in fact, it generally isn't a good idea to let the view and persistence layer concern themselves with what the other does. That's what the layer between them is for.
So, in your situation I'd have a single DateTime object under the hood that stored off that incident information and then break it apart into its constituent pieces for display/entry, reassembling it before you persist it.
Generally speaking, the big rookie mistake I initially made when writing my first ASP.NET MVC 3 app was to let Entity Framework spit out some generated objects that mapped to DB tables and then pass those to the View. Once I started writing and using viewmodels to transform the data into something that was presentable and then just let that layer transform between the viewmodel/view world and the underlying model/persistence layer world, things were much easier.
I think you should have only one field in your database. Options 2 and 3 works well, and I used both with good results in simple sceneries.
But I think you will want to take a look to Editor Templates. Using it well can make things better when the scenary becomes complex: http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html If you make an editor template for this case, you will be able to reuse it along all your web app.
The tutorial is for ASP.NET MVC 2, but It's still valid in ASP MVC 3.
Hope it helps.
I believe that in general, you will never quite have a situation where your "ViewModel" matches your "Model" perfectly. There's always going to be one field here and there that you don't want written to the DB.
I think Option 3 is pretty much what I am advocating here.
Here's an example I like to describe. For my domain, I have a model for customer. This model would include UserName, FirstName, LastName, Password, EmailAddress, and ZipCode.
I may have views for Login and Registration. My login view will only be concerned with UserName and Password. My Registration view will be concerned with UserName, FirstName, LastName, Password, ConfirmedPassword, EmailAddress and ZipCode. As you can tell, these views do not map directly to the domain model. For example, the registration view needs to work with Password and ConfirmedPassword and plus the other properties in the domain model, but the problem here is that customer domain model does not include ConfirmPassword. With this in mind, it would be preferred to create a model view that is specific to the data the view needs. So I would create a view model call CustomerRegistrationVM and CustomerLoginVM.
Usually my controllers call services to retrieve data from a repository. The repository returns data per the domain model to the service. The service translates the domain model to the correct view model.
When the data needs to be updated or saved, the controller passes the view model to a service to save the data. It's the responsibility of the service is to translate the view model to the domain model and call the repository. There are situations where the service does not need to translate the view model to the domain model, but just passes the data that is needed by the repository.
精彩评论