A good way to keep your entities clean

by Leon Cullens 18. maart 2012 16:28

This tutorial will show you how to keep your entities and your views clean by translating entities to viewmodels. It is a good practice to do this because it keeps your files clean, it avoids certain security problems and it's more flexible, as you will read in this article. The examples are using C# and ASP.NET MVC, but the concept is pretty generic and can be applied to virtually every programming language or framework.

The problem

Let's say we have a Person entity:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Password { get; set; }
    public string Email { get; set; }
    public bool IsAdmin { get; set; }
}

Pretty straightforward, nothing special to see here. Now that we have this entity, we want to fill it with data. We're going to create a new 'person'. We could just return this entity to our view so we can fill it with data and persist the whole thing. But this leads to multiple problems:

  1. We probably don't want a user to pick his own ID.
  2. We want the user to confirm his password, so we'll probably need 2 password fields.
  3. We don't want the user to choose if he wants to be an admin or not (although that could lead to some cool experiments)
  4. If we are changing our database (and therefore the entities), our forms will rely on entities that are different than we intended in the first place.

The solution

So now that we have our problem, we can start looking for a solution. One solution is that we edit our entity to have two password fields, and exclude the Id and IsAdmin fields when the data comes back from the view. This method is pretty bad because now we have to add another (useless) password field to the database, or have a database table that doesn't map to it's entity. Another problem this raises is that people can modify the POST request to include a 'IsAdmin = true', making him an admin (this is referred to as mass assignment by some people). This problem could be solved by excluding all the fields we don't want the user to edit, and overwrite them with our own data. But what if we forget this one time?

A second, and better, solution is to create a special 'model' that is passed to the view. I call this a ViewModel, but you can call it whatever you like. This ViewModel only has the data that the view really needs, along with some ASP.NET MVC annotations to let ASP.NET know how to render the form:

public class NewPersonViewModel
{
    [Required]
    public string Name { get; set; }

    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [EqualTo("Password")]
    public string PasswordConfirm { get; set; }

    [Required]
    [Email]
    public string Email { get; set; }
}

As you can see, we no longer have an ID field, an IsAdmin field and we now have two password fields.

When we submit the form, this ViewModel will get submitted to our controller, where we can 'translate' the ViewModel to an entity so we can save it to the database. We can do this manually by creating a Person object and filling it with the corresponding properties from the NewPersonViewModel object, or we could let AutoMapper figure this out for us. AutoMapper is a handy little tool to map objects of type A to type B by convention, meaning that it will map properties of type A to it's corresponding properties of type B by looking at the name of the property. Our NewPersonViewModel's 'Name' property will automatically be mapped to our Person's 'Name' property because they have the same name. As you can see, this tool can save you quite a bit of time.

The code to do this:

public class PersonController : Controller
{
    public ActionResult New()
    {
        return View();
    }

    [HttpPost]
    public ActionResult New(NewPersonViewModel data)
    {
        if (ModelState.IsValid)
        {
            Mapper.CreateMap<NewPersonViewModel, Person>();
            Person person = Mapper.Map<NewPersonViewModel, Person>(data);

            // save the person to the database

            return RedirectToAction("Index");
        }

        return View(data);
    }
}

Validation

Maybe you already thought about validation. What if I have validation in my entities (well, probably not in the POCO classes but somewhere else, otherwise they wouldn't be 'Plain Old CLR Objects' anymore) and I want the ViewModels to have validation too? Do I need to duplicate my validation code?

Sometimes the answer is yes, your ViewModel will probably need some specific validation (such as our 'password 1 must match password 2' requirement), and your entity will probably need some specific validation to satisfy your database as well ('the ID field can never be null'). However, as far as I've heard, AutoMapper can 'copy' your validation rules from object A to object B in the newest version, so you probably don't have to duplicate all your validation logic. I haven't tried this myself though, so I can't really say if it works good or not.

Conclusion

As we have seen, converting entities to view-specific models is a clean way to avoid many problems with flexibility, security, etc. It does add a little extra overhead, but it's well worth the extra effort. We can  do the mapping between objects manually or automatically by using AutoMapper. I hope this tutorial has been useful to anyone who didn't understead this technique yet. Feel free to share your own thoughts!

Tags: , , , , , ,

Architectural patterns

Comments (2) -

Dotnet techy
Dotnet techy India
28-3-2012 8:50:46 #

Great article

We can also submit our .net related article links on http://www.dotnettechy.com to improve traffic.

This website also have directory submission for .net related website / blog only

Reply

Leon Cullens
Leon Cullens Netherlands
28-3-2012 22:12:42 #

Thanks for that Smile I'm always looking for good site to promote my blog items.

Reply

Pingbacks and trackbacks (1)+

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

about

Name: Leon Cullens
Country: The Netherlands
Job: Software Engineer / Entrepreneur
Studied: Computer Science 
Main skills: Microsoft technology (Azure, ASP.NET MVC, Windows 8, C#, SQL Server, Entity Framework), software architecture (enterprise architecture, design patterns), Marketing, growth hacking, entrepreneurship

advertisements

my apps