I just want to make sure I understand correctly the best practices for ASP.NET MVC2 with LINQ-TO-SQL.
Please correct me if I am wrong at any of the following points:
LINQ TO SQL generates classes for
you, based on your tables
The generated classes are Models
Those are the models we are supposed to use in the Views
If we want to add validation to the models, we extend the partial class and set data
annotations. Something like this.
Generally my question is about the data validation. What I used to do is create a "shadow" Model for each of my LINQ-to-SQL generated classes and put the data validation there. Then, in the controllers I was creating an instance of the "shadow" model and also retrieve data (using Repository pattern). Mapped from the entity to the shadow model and passed it to the view. So, something like that (in the Controller):
// Car is class generated by LINQ-to-SQL, based on the Car table
// Use repository class to retrieve the data (Car)
Car car = myDatabaseRepository.GetCar(1);
// CarModel is my 'shadow' model, which has all the data validation.
// For example, it makes sure Year is before 2010 (let's say).
CarModel carModel = new CarModel();
carModel.Year = car.Year;
carModel.Make = car.Make;
carModel.Model = car.Model;
return View(carModel);
This is wrong, right (no pun intended)? It should have been only:
// Car should have been extended (as partial) and data annotation
// should have been in the extended class, rather than a whole separate
// model class.
Car car = myDatabaseRepository.GetCar(1);
return View(car);
Right?
I think it is a best practice to have a ViewModel (what you termed "shadow" model) that is used to pass only relevant data model information to a view and incorporating UI validation metadata. You can also use a library such as AutoMapper to copy over the values, rather than coding each one by hand.
A Table = Model approach can work in very simple scenarios (few tables + simple UI exactly matching database schema). In order to save yourself a lot of pain later on it is recommended to use ViewModels.
Related
In an mvc project, could someone explain to me the difference between a model and a view model?
My understanding is that a view model reperesents the data for view eg. cshml, but a model represents the data for a partial view. Would this be correct. I have seen the names used in different situations which confuses me so looking for direction on this.
Models are your domain. For example we might have a customer model. We can use this customer in our domain. We can place orders for this customer. We can update the customers contact details, and so forth.
// Domain object, encapsulates state.
class Customer
{
public void PlaceOrder() {...}
public void UpdateContactDetails() { ... }
}
View Models are a way of presenting the data in an easy way. For example, we might have a customer view model. This would be a simple DTO (Data Transfer Object) which allows us to expose the customer to a view. Often view models are created from models - some form of conversion often takes place.
// DTO - exposes state - no domain logic
class CustomerViewModel
{
public string Name { get; set; }
public int Id { get; set; }
}
The benefit of using a view model rather than using your domain objects in your views is that you don't have to expose the innards of your domain to ease presentation logic. I should add that view models are a way of controlling model binding, e.g. if you expose a database record you probably don't want the whole record to be bindable. Using a view model means only those parameters on the model will be bound. Therefore using view models is important from a security point of view. The alternative here is to use whitelists to control what is used during the model binding process - naturally this is tedious and prone to error.
In terms of ASP.NET MVC - the word model is used somewhat interchangeably. In a "real world" project, your domain is likely complex and will not reside inside a Web App, chances are you'll include some other dependency. Therefore the "models" you'll use will be View Models.
In general, in the ASP.NET world, when people refer to models to refer to 'domain models' which are often a 1-1 mapping between say a database table and a C# class.
When referring to view models, these are convenience classes which aid the passing of data between the view (.cshtml) and controller.
The view models should contain data relevant to the view, which may contain aggregation data of the domain model (e.g. a property called 'FullName' which is the combination of 'FirstName' and 'LastName') or things like paging info etc.
Personally I prefer to use view models to present data in simple forms to the view, and I make the controller actions take instances of a view model, construct domain models and act on them, either directly or through a service layer.
I'd say that is general a view model holds the data for a specific view/screen/partial view and a model is rather the object representing the business object or entity.
Please look into the following posting, your question was successfully answered:
ASP.NET MVC Model vs ViewModel
Hope this helps
I am trying my hands on MVC 2, ADO.NET EF and POCO. I have generated my entity classes in a separate library using POCO generator.These POCO entities are used as ViewPages (Not sure if that's the right way to design or do I need separate ViewModels classes ?)
Now, if I take case of a simple scenario where I need to add an Employee object( which is related to a Department Master), what then should be the recommended way to transfer these objects between layers.
Layered structure of the application is somewhat like this :
I have thought of various alternatives:
I have a method in the Employee Controller which is named AddEmployee() which accepts the FormCollection as parameter. Within the form collection I get posted data such as Employee Name, Age , Salary etc and the ID of the Selected Department .
1.) One way is that I can create another DTO say EmployeeDepartment DTO which will be used to map values from FormCollection as is. I can then break them at manager layer and use them to create entity objects i.e Employee Object and refer department by query similar to this:
e.Department = Department.where(i => i.deptId == empDepDto.dept_id).first()
I am not a big fan of this and feel that every time there is a relation involved I have to add a DTO and then map it to my entity class.
2.) Second is probably the worst, i.e passing each object as parameter and then couple them in manager layer.
3.) Use POCO as is, Create a Employee Object and Deparment Object at controller layer and pass the POCO object
public void AddEmployee(FormCollection formCollection)
{
Department d = new Deparmtent; d.id = ""; //based on the dropdown value
d.name="" //based on the dropdown selected text;
Employee e = new Employee; e.Name. e. sal....
e.Department = d;
EmployeeManager.AddEmployee(e);
}
But at manager layer I think , I still need to recreate the reference to the Department using LINQ which again is repetitive and doesn't seems to be a clean solution.
Are there better ways of handling this ? Looking for recommendations and best practices.
Firstly, is there any reason you're not using MVC version 3? There's no major breaking changes, so may as well upgrade?
Secondly is there a reason for using FormCollection rather than the strongly typed model-binding? Just change your views to use the strongly typed HTML helpers ( like <%: Html.TextBoxFor(m => m.Property) %>), or make sure the name attributes match the property names, and have your controller receive the type, and model binding will do the rest. There's plenty of tutorials showing this, and articles explaining it. Model binding will work with a name/value collection, like that posted as a form, or against JSON data, or you can find/write custom model binders that work against whatever wacky serialisation protocol you want.
One thing to watch though when passing the actual entity types that Entity Framework will store around, is that you have to be careful when updating existing objects, or with foreign key references to existing objects - all your objects must be attached to the right Entity Framework context. To achieve that you will often see the objects received by the controller having their properties copied to a freshly retrieved entity from a context, either manually or by an object mapper of some kind.
Make a seperate project called "BusinessObjects" or "Model" which contains your POCOs. Then use strongly typed model-binding for MVC and you'll be set.
The method signature will look something like this:
// In your Controller
public void AddEmployee(Employee newObject)
{
YourDataContext dc = new YourDataContext();
dc.Employees.Add(newObject);
dc.SaveChanges();
}
I've found this text in Prism documentation. I'm starting on MVVM and I'm at lost. Can (should) I bind model properties in the view or I must create a viewmodel with a proxy property for every property in the model?
The model classes typically provide
property and collection change
notification events through the
INotifyPropertyChanged and
INotifyCollectionChanged interfaces.
This allows them to be easily data
bound in the view. Model classes that
represent collections of objects
typically derive from the
ObservableCollection class.
EDIT: Here is some extra info to help. I'm building a personal project from the ground up (so I'm designing the models too), this is the first time that I use MVVM and I want to learn properly.
My model is very hieraquical, having classes with list of more class with more list inside, building a complex tree of information. I was trying the "standard" MVVM approach, build the model with POCO and no notifications, and using List. Then building the ViewModel with proper notifications and using ObservableCollections.
The problem is, the way it is going, I'm almost reconstructing my whole model as a ViewModel AND having to keep the data synched between the to (the ObservableCollection to the List). Then I read that on the Prism docs and wondered if I should have all that trouble or just create a root ViewModel for logic and bind all the rest to the model itself.
It depends really, if your model already implements INotifyPropertyChanged and/or IError info you might want to bind right to the model property. However if you want to do special validation and other stuff that the model knows nothing about you add the property wrappers in your view model.
This article gives a good example of a hybrid: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
Often my MV properties look like this and thats quite normal:
public string Symbol
{
get { return Model.Symbol; }
set { Model.Symbol = value; this.NotifyOfPropertyChange(() => this.Symbol); }
}
I often do NOT implement INotifyPropertyChanged in the model and thus often I have to write the wrappers.
EDIT: In response to your additional information: It can be a bit tricky to to keep the collections and lists in sync. In your case what I would do is to create a view model for each model class, but NOT wrap all the properties just access them like this: {Bindng Customer.Name}. But of course you have to create a wrapper for the collections which contain view models. The Prism documentation is, as they say themselves, just guidance, if your scenario needs a different approach then this is fine.
Take a look at this code. I only wrap the collections and the properties I will access through the model. This gives you the best of both worlds. Then IF you need a special property that does not belong into you model you can add it to the view model (see the CustomerViewModel), or if you need special notification for a certain properties.
class CompanyViewModel{
public CopanyViewModel(Company c){
foreach(var customer in c.Customers)
Customers.Add(new CustomerViewModel(customer);
}
public Company Company {get;set;}
public ObservableCollection<CustomerViewModel> Customers {get;set;}
}
class CustomerViewModel{
public CustomerViewModel(Customer c){
Customer = c;
}
public Customer Customer {get;set;}
public Brush CustomerBackground{
get{
if(Customer.Active)
return Brush.Greeen;
else
return Brush.Red;
}
}
}
(This code might not work, I just typed it in here.)
Now, if you need changed notification for all models and all properties you have to either implement it in you model or in wrap all properties in a view model.
I have an MVC2 application with the following classes:
-OrderModel
-LineOrderModel
-OrderController
-LineOrderController
In the OrderController class I'm recollecting some values of a web form . Until now, I created instances of each order line (LineOrderModel class) and OrderClass inside of the Controller.
I was trying to create a OrderFacade class in order to encapsulate the different things to do when creating an order.
So in that class I created a method like this:
public void saveOrder(int idProvider,decimal? price)
{
// Here I create instances of OrderModel and LineOrderModel
// and assign their properties
}
but my problem is I don't know how to pass all the order lines captured from the web form.
I think it doesn't make sense to create and pass to that method a List with orderLines class (because the point of this is to operate with the Facade, not with the class directly)
How could I encapsulate the different lines (all with properties like numberUnits,idProduct ...) into a List of generic objects, each one with these properties?
Maybe something like a List<List<object>> ?
Thanks in advance!
Sounds like you don't need facade. Facade would be good choice if you use data transfer objects (DTOs) between your business logic and application logic (controllers) - in such scenario DTOs can also be view models (I guess orthodox MVC developers will don't like this idea). Facade would take DTOs and convert them into some business or domain objects.
But in your scenario you simply need to fill data directly to your model classes - that is purpose of view model classes to use them in views and controllers. Using any kind of property bags to transfer data from controller to business logic is not a nice solution.
I've been chugging along OK with the use of data annotations made on buddy classes so far.
When it comes to a more complex view that requires a custom view model--one that includes a few select lists, for example...would I need to then transfer my validation attributes to the view model class?
I was planning to pass the full custom view model to populate an "Edit" view, but was hoping to just receive a simple object in my "Save" action.
Where are the flaws in this plan, or is the whole thing just one big pile of fail in the first place?
Thank you.
You're still validating that data that is ultimately going back into the database. So in order to keep your application DRY, you are best off to use the Buddy Classes for the original Model.
Edit
note: this doesn't exactly have anything to do with your question
I personally prefer extend the original Model for anything "Edit" related and I prefer to use a ViewModel for "Display" only (Details pages, List pages, etc).
Example: here's my buddy class, and in it I've added a "RegionName" property that I use in the Edit Page display, but it doesn't have anything to do with the database. You can do a similar thing with custom input data that you want to validate before manipulating it into "database usable" data. I use the RegionID in the database, but I prefer to use the friendly name for the visitor instead of the ID integer
<MetadataType(GetType(UserMetaData))> _
Partial Public Class User
Public RegionName As String
End Class
Public Class UserMetaData
<DisplayName("region name")> _
<Required(ErrorMessage:="region name is required.")> _
Public Property RegionName As String
End Class
Your view model will still inherit the validation from your base model.
Don't know if this helps but I put my validation attributes against my model so that wherever i use the model i get the same validation. not ideal for some projects i realise.
actually, i put the attributes agains a partial class rather than my model because 90% of the time my model comes from a linq 2 sql file in my data repository
my controller then simply checks if the model is valid or not and the view does nothing except display data and errors really.
unsure if this is what you're asking though