asp.net mvc model the same as (database mapped) object? - c#

I have the following setup: fluent nhibernate + asp.net mvc 4.
I have a seperate project in VS where all my objects are stored, these objects are directly mapped to the database.
However, to display data from these objects in the views, I need 'models'.
Do I need to create new model objects, based on these database mapped objects, or can I just pass these database objects as a model to the view? (is this a good idea?)
Thanks!

In my opinion you should create additional ViewModel classes. If some changes are to be made to the data that get displayed, it's easier to just modify these models; your domain mappings will not be affected by some particular "rendering" circumstances.
Another advantage would be that you can decorate the properties with formating attributes, without enforcing these settings on future projects that depend on your domain.
For example, say you have the following Customer class in your base project:
public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
}
You can add a [Required] attribute on the Name property to make it mandatory. If for a particular project you need to also make the Address property mandatory, you would decorate it with another [Required] attribute. If you directly use the domain model classes, you will enforce that the Address property would always be required, even though the project requirements would not state that. This can be further extended to different validation attributes and also additional data that you may want to sent to the view along with the model (such as composite fields).

This is largely a design decision that depends on the size of the project, etc. Without getting into too much detail, the short answer is yes, you can use your database objects/models directly in your Views.
Sometimes it may be desirable to create specific view models if you only want to show a subset of the fields, or do different validation than the database in your View. You can then can validate this view model in your controller and if everything is okay, map it to your nHibernate models.

Related

Are classes generated by Entity Framework database classes or business classes? [duplicate]

This question already has answers here:
Should Entities in Domain Driven Design and Entity Framework be the same?
(4 answers)
Closed 5 years ago.
I have a three tier app with a class library as the Infrastructure Layer, which contains an Entity Framework data model (database first).
Entity Framework creates entities under the Model.tt folder. These classes are populated with data from the database.
In the past I would map the classes created by Entity Framework (in the data project) to classes in the Domain project e.g. Infrastructure.dbApplication was mapped to Domain.Application.
My reading is telling me that I should be using the classes contained in .tt as the domain classes i.e. add domain methods to the classes generated by Entity Framework. However, this would mean that the domain classes would be contained in the Infrastructure project, wouldn't it? Is is possible to relocate the classes generated by Entity framework to the Domain project? Am I missing something fundamental here?
I think in the true sense it is a Data Model - not a Domain Model. Although people talk about having the Entity Framework Model as a domain concept, I don't see how you can easily retro fit Value objects such as say amount which would be represented in the true domain sense as such:
public class CustomerTransaction
{
public int Id { get; set; }
public string TransactionNumber { get; set; }
public Amount Amount { get; set; }
}
public class Amount
{
public decimal Value { get; }
public Currency Currency { get; }
}
As opposed to a more incorrect data model approach:
public class CustomerTransaction
{
public int Id { get; set; }
public string TransactionNumber { get; set; }
public int CurrencyType { get; set; }
public decimal Amount { get; set; }
}
Yes, the example is anaemic, but only interested in properties for clarity sake - not behaviour. You will need to change visibility of properties, whether you need default constructor on the "business/data object" for starters.
So in the domain sense, Amount is a value object on a Customer Transaction - which I am assuming as an entity in the example.
So how would this translate to database mappings via Entity Framework. There might be away to hold the above in a single CustomerTransaction table as the flat structure in the data model, but my way would to be add an additional repository around it and map out to the data structures.
Udi Dahan has some good information on DDD and ORM in the true sense. I thought somewhere he talked about DDD and ORM having the Data Model instance as a private field in the domain object but I might be wrong.
Also, that data model suffers from Primitive Obsession (I think Fowler coined it in his Refactoring book - although it Is in his book) Jimmy Bogard talks about that here.
Check out Udi Dahan stuff.
You should move your model to a different project. That is good practice. I don't quite get it what you meant by "moving to to Domain project" Normally entity framework generated classes are used as a domain model. No need for creating "different" domain model from this. This model should be use only near to database operations, whereas web(window) application should use only DTO (Domain transfer objects)
I don't know if you use it or not - but this is a nice tool allowing for recreating model from the database :
https://marketplace.visualstudio.com/items?itemName=SimonHughes.EntityFrameworkReversePOCOGenerator
This allows to store model in classes (instead of EDMX) Someone refers to it as "code first" but there is a misunderstanding. One can use this tool to create model and still be on "database first" This is done simply to omit using EDMX as a model definition.
You can relocate the entity classes by creating a new item in your Domain project: DbContext EF 6.x Generator (not sure of the name and you might have to install a plugin to get this item in the list, also exists for EF 5.x).
Once you have created this new item, you have to edit it to set the path of your EDMX at the very begining of the file. In my project for example it is:
const string inputFile = #"..\..\DAL.Impl\GlobalSales\Mapping\GlobalSalesContext.edmx";
You will also need to edit the DbContext.tt file to add the right using on top of the generated class. At each change you've done on the EDMX, you also will have to right click the generator and click: "Run custom tool" to generate the new classes.
That being said, is it a good practice? As you can see that's what I have done in my project. As long as you do not have EF specific annotations or stuff like that in the generated entity classes, I would said that it is acceptable.
If you need to change your ORM, you can just keep the generated classes and remove all the EF stuff (.tt files, etc) and the rest of your application will work the same. But that's opinion based.

How to correctly parse complex viewmodel to separate domain models in ASP.NET MVC?

I wonder how could I solve the following case : there are a form on website where manager input very big amount of data to Viewmodel and pass to server-side.
class CitizenRegistrationViewModel {
public string NationalPassportId { get;set; }
public string Name { get;set; }
public List<string> PreviousRegisteredOfficeCodes {get;set;}
// about 30 fields like strings, Booleans, HttpBasedFiles (pdf,jpg).
}
And the problem that in domain this data need to be logically separated and stored in different tables (classes in EF) like CitizensNationalPassportsTable, CitizensWorkingPlaceRecordsTable, etc. There are no complex class Citizen with properties like :
public class Citizen {
public ICollection<CitizensWorkingPlaceRecords> workingPlaces
// etc...
}
but this properties are separately stored in different tables with no one-to-one or one-to-many relations (no FK here) . The only NationalPassportId property could be used as navigation key (unique per user and all records related to user in different tables contains this key).
Should I write big amount of code to parse Viewmodel to domains models like :
public void CitizenRegistrationViewModelToDomainModel(CitizenRegistrationViewModel model){
CitizenNationalPassport passport = new CitizenNationalPassport(model.NationalPassportId);
CitizensWorkingPlaceRecord workplace = new CitizensWorkingPlaceRecord(model.PreviousRegisteredOfficeCodes, model.NationalPassportId);
// 12 extra objects need to create...
db.CitizenNationalPassports.Add(passport);
}
Or is there any more correct approach to handle this problem? I wanted to use AutoMapper, but is it the best solution?
I can't change business models' logic, as it is a legacy project.
You should have a set of classes that represents the data that the browser is exchanging with ASP.NET MVC. Let's name them for example, Input Models. In this classes you have metadata attributes, custom properties and many things that are relates with the exchange between browser and web server.
You should have another set of classes that represent your database structure, those are your Entity Framework POCO classes. Let's name them DB Models. It does not matter how POCO and fancy they are, they always map to tables and columns, so they are always tight to the DB structure.
You should have another set of classes that are your domain classes, the classes you use when operating objects in your business layer.These are binding/persistence/representation agnostic.
You should have a repository that knows how to persist a domain entity. In your case it will be a class that knows how to operate the DB models and the DbContext.
Then, when you get input from your browser, you bind that data to the input models and those are passed to the controller (this is done automatically by the DefaultModelBinder or you can use your own IModelBinder).
When you get an input model, you have to create a new domain entity using that data (in case that is an actual new entity). Once you have your domain object ready, you pass it to the repository to be saved.
The repository is responsible of knowing how to save the domain entity in the database, using the DB models.
In essence, the Controller or the business service instance you operate in the Controller's action context should be responsible of articulate the interaction between these elements without them knowing each others.
AutoMapper or an alternative could be used to automate the mapping from View model to Domain models, but this only makes sense if properties are named identical in View and Domain models. If this is not the case you'll end up writing mapping rules which doesn't help you. It just moves code from your current mapping classes to the AutoMapper configuration. So, if you're in a position to modify your viewmodels I'd go for AutoMapper or anything similar, if not I'd use what you currently have.

Using Hardcoded Types in an ASP.NET MVC Application w/ Entity Framework

What is a good way to handle/organize/use Hardcoded Types with an ASP.NET MVC application using Entity Framework?
By Hardcoded Types I mean static types defined in the business logic that will not be manageable by the User, only the developer. i.e. ProductTypes, CustomerStatuses, etc..
I am trying to achieve a couple of things:
Works well with Entity Framework data binding
Will be able to populate MVC View DropDownLists easily (assuming my ViewModel will be able to have a list of the type)
Will have a reliable valued stored in SQL (whether it is a string or Id)
Will be able to use in if/case statements throughout business logic
Using Enums:
For example lets say I have a Product entity which has a Type field.
My first instinct is to create an Enum directly in the class called ProductType with its values. However if I use enums throughout I am worried that I won't be able to accomplish the 4 above requirements.
Using GlobalConstants
In the past I have also created a GlobalConstants file and just created a bunch of constant strings so I could use them throughout the BusinessLogic. Then in the database I would create a TypeList table (TypeName, TypeValue, FriendlyName, etc..) that stores all of these values. So basically the TypeList table would always have to stay in sync with the GlobalConstants or something would break.
Something is telling me Enums is perfect for these hardcoded types
Just create a model for ProductType. Example:
ProductType: {int id, string name}
In the Product model class add:
public ProductType Type { get; set; }
So basically you can store the types in database.

Validation in data first approch

I am implementing a project using mvc 4 and entity framework.
where i used data first approach. and i am implementing a partial class for my models for various business logic.
my question is how can i set validation rule on my properties. shown in below.
[Required]
public string FirstName { get; set; }
if i manually added this code "[Required]" on a property (entity framework generate models).
and then if i need to change model for database changes. then all my validation rule is gone
how can i over come this problem, without using code first approach.
As you've found out you should never edit the generated files since changes are lost when you regenerate them.
A better architecture than to use the entities as models for your views is to insert a separate View Model between the view and the entity. The view model should correspond closely to the needs of the view and often retrieves data from several underlying entities.
The attributes then goes on the view model properties instead of on the entities.
View models also remedies the risk of mass assignment vulnerabilities in your application, which are particularly dangerous if you are using lazy loading in your entities.
Another way around this (using CodeFirst) is to use a Fluent Validation. The CustomerValidator will always point at the regenerated Customer class (unless you change the Customer class name obviously)
using FluentValidation;
public class CustomerValidator : AbstractValidator<Customer> {
public CustomerValidator {
RuleFor(customer => customer.Surname).NotNull();
}
}

What's the recommended approach for getting lists for multiple selections and displaying them in MVC?

I've searched both SO and Google on this but have not found a relevant / acceptable answer.
Background:
* Using MVC 4.5
* I have some Generic Repo<T> that I am using over the top of EF5, which in turn are accessed by generic Service<T>
* I have domain models and view models and I am using Automapper to map between them, this mapping happens in the Service layer
* On top of that, I have my Controllers which again are generic as much as possible.
So, to the question; I have a couple of scenarios where I need to present a list of options to the user and they have to select one or more. The options are user specific, so my domain User has a List<Location> which is their saved locations, and when adding / modifying, an Item, they are required to select at least one Location.
I am resisting the temptation to fetch that List<Location> in my controllers because I want to keep them generic and slim, but at the same time, I'd rather not have two properties in my ItemView model, one for AvailableLocations and one for SelectedLocations, because this model is used not just for adding / modifying but for search results etc.
Options:
* Should I introduce a different model for adding / modifying an Item, e.g. ItemInput?
* Should I use some custom mapping and get Automapper to get the list of available locations?
* In which layer should I fetch these available locations?
What are people's suggestions on a neat and generic approach to this please?
Many thanks!
I would do something like this:
public IEnumerable<Location> GetLocations() {
return db.GetAll();
}
Then inside of your controller (I followed this from MVC scaffolding):
ViewBag.Locations = new SelectList(service.GetLocations, "name", "id");
(or your own checkbox list)
and put a listing control on the HTML/View page.
The reason I believe this is the best method is because the logic all resides inside the service. If you put it in your DTO/data model you may come against this problem:
What happens if you require additional logic to pull back locations? i.e. sub locations of locations.
You change your service (or override) to reflect the new changes, and this logic would go inside of the service:
public IEnumerable<Location> GetLocations(string parent) {
return db.GetAll().Where(loc => loc.parentname = parent);
}
p.s. I never use generic services, the reason I have a service is because some of the data access it provides contains logic that is not meant to sit with the generic DAL.
I could make an interface or abstract service to make my life a little easier for common operations between services but once you define say a concrete, a UserManagementSerive surely you are saying you want to manage an object that has Users, and Locations and Items each having its own specific functionality?
I don't think there is only one possible answer to this question.
I would recommend a simple, but not-so-generic approach. I would write what's called ViewModels, i.e. model classes that are related to your specific views. Then I would get your available locations from the controller, and populate an instance of the ViewModel in your controller using the fetched locations.
Basically I would expose some services like:
IEnumerable<Location> GetAvailableLocationsForUser(string userName);
Do note I've used IEnumerable<T>, not IQueryable<T>. Because the implementation will actually request the database, as it's too much bug-prone (at least IMO) if it's the role of the controller to do so (remember the deferred execution of IQueryable<T>).
And it returns a domain instance, i.e. an entity, not a mapped model. I wouldn't personally deal with anything but domain classes in the service layer. There could be domain classes that are not entities, but compositions of entities for example. This could help making efficient requests and avoiding using lazy-loading and deferred execution in the controllers. This is helpful when the controller needs a whole object graph and not only an entity.
Then I would write Models and ViewModels like the following, in the web application assembly:
public LocationModel
{
...
}
public CreateItemViewModel : ItemModel
{
public List<LocationModel> AssociatedLocations { get; set; }
public List<LocationModel> AvailableLocations { get; set; }
...
}
There are basically Models (ItemModel and LocationModel), which are objects related to the web application. This means there could be some web-related things in those models, for example computed read-only properties or attributes on properties (DisplayAttribute...etc.).
I would write those models multiple times, actually, because I don't think this is something that could be generalized: for example, one view could require the use of a navigation property while another view wouldn't. So this changes the depth of the mapping process depending on the views that uses the model. And I wouldn't use AutoMapper at all (only hand-written mappers).
There are also ViewModels (CreateItemViewModel), which are objects related to a single view (for example the view that allows to create an Item in this example). The difference between Model and ViewModel is that the ViewModel is related to a single view (and named according to this view). On the other hand, Models are related to multiple views (its namespace would help to know which views. For example, xxx.Item.Models for Models related to all views in the xxx.Item directory). ViewModels are built from scratch in the controller (or in a separate mapper) based on the domain classes.
In the above example, you could build a domain classes that would return AssociatedLocations and AvailableLocations, but it would require your service layer to be aware of the web part (I mean, your service interface and domain classes would know which properties are needed for a particular view). I'm not sure those properties are actually related to a single view in your application, but if it's not the case, you could also build a domain class as a composition of entities that would return AssociatedLocations and AvailableLocations:
public ItemExtended : Item
{
public List<Location> AssociatedLocations { get; set; }
public List<Location> AvailableLocations { get; set; }
}
ItemExtended GetItemExtendedById(long idItem);

Categories