Entities VS Domain Models VS View Models
Solution 1:
I think you're just having issues with defining what each layer is and what role it is playing in your solution.
Data Tier
Your data tier is simply your database / SharePoint list / .csv file / excel sheet... you get the idea, it's simply where your data is stored, and it can be in any format. So remember that the data tier is nothing more than just data.
// ----------------------------
// Data tier
// - MySQL
// - MS SQL
// - SharePoint list
// - Excel
// - CSV
// - NoSQL
// ----------------------------
Data Access Layer
This layer abstracts away your data source, and provides an API in which the rest of your application can interact with the data source.
Consider that our data source is an MS SQL Database and that we're using Entity Framework to access the data. What you'll be attempting to abstract away, is the database and Entity Framework, and have a Data Repository
for each Entity
.
Example...
We have a Customers
table in a MS SQL Database. Each customer in the customers table is an Entity
, and is represented as such in your C# code.
By using the repository pattern, we can abstract away the implementation of the data access code, so that in future, if our data source changes, the rest of our application wont be affected. Next we would need a CustomersRepository
in our Data Access Layer
, which would include methods such as Add
, Remove
and FindById
. To abstract away any data access code. The example below is how you would achieve this.
public interface IEntity
{
int Id { get; set; }
}
public class Customer : IEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime RegistrationDate { get; set; }
}
public interface IRepository<TEntity> where TEntity : class, IEntity
{
TEntity FindById(int id);
void Add(TEntity entity);
void Remove(TEntity entity);
}
public class CustomerRepository : IRepository<Customer>
{
public Customer FindById(int id)
{
// find the customer using their id
return null;
}
public void Add(Customer customer)
{
// add the specified customer to the db
}
public void Remove(Customer customer)
{
// remove the specified customer from the db
}
}
The data access layer belongs in between the data layer and business logic.
// ----------------------------
// Business logic
// ----------------------------
// ----------------------------
// Data access layer
// - Repository
// - Domain models / Business models / Entities
// ----------------------------
// ----------------------------
// Data tier
// - MySQL
// - MS SQL
// - SharePoint list
// - Excel
// - CSV
// - NoSQL
// ----------------------------
Business layer
The business layer is built on top of the data access layer, and does not deal with any data access concerns, but strictly business logic. If one of the business requirements was to prevent orders being made from outside of the UK, then the business logic layer would handle this.
Presentation tier
The presentation tier simply presents your data, but if you're not careful about what data you present, and what data you allow to be posted, you'll set your self up for a lot of headaches down the line, which is why it's important to use view models, as view models are a presentation tier concern, the presentation tier doesn't need to know anything about your domain models, it only needs to know about view models.
So what are View Models... They're simply data models which are tailored for each view, for example a registration form would include a RegistrationViewModel
, exposing these typical properties.
public class RegistrationViewModel
{
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
}
The presentation tier also handles input validation, so for instance validating whether an email address typed has the correct format, or that the passwords entered match is a presentation tier concern, not a business concern, and can be handled by using Data Annotations
.
public class RegistrationViewModel
{
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[Compare("ConfirmPassword")
public string Password { get; set; }
[Required]
[DataType(DataType.Password)]
public string ConfirmPassword { get; set; }
}
The reason it's important to use View Models is because the Business Models belong to the business layer, and they include data which should remain private. For instance, if you were to expose the Domain Model in a JSON response, it would expose the users entire data, their name their address as you're not being selective about what is being exposed and what isn't, but using whatever that seems to be working.
I should also point out here that there is a difference between domain models
and entity models
. There's already an answer that goes into a lot more detail here
Cross cutting concerns
I'll keep this brief:
- Exception management
- Mapping of View Models to Domain Models.
- AutoMapper
Solution 2:
I'm not an expert, but I will share my 50 cents on the topic.
View Model
I would like to share your concern about ignoring the View Model.
Using view model you can:
- Select only the data you need from the domain model
- Format the data you need in the right way to the presentation (e.g. format price decimal (100.00) to string (€100.00))
- You can use DataAnnotation on your view model.
So, I also consider it a bad design, but others might have a different opinion.
Remember, the business layer doesn't know anything about the view model, so you should map it in the controller.
Entities vs domain model
I would start it simple, using a POCO as domain model that can be persisted with an ORM or a NoRM. For most of software developed in the world, it will not hurt your system much and it's also simple.
In the future, if you start using web services for some reason, you might need to consider the use of DTOs (Data Transfer Objects) for remote calls. When there, what you can do is to have another layer, responsible for mapping your domain model to the desired DTO. This layer would be used only in the remote call (web service), keeping the view model for the presentation.