Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map Entity Framework model classes with Business Layer class in n-tier architecture - ASP.NET-MVC

I am working on e-tier architecture within MVC framework (ASP.NET MVC5, Entity Framework 6). My application is divided into three sub-projects which are Business-Layer, Data-Access-Layer, Repository (This include repository and Unit of Work) and ASP.NET MVC web-app. I am struggling to understand mapping between business data and entity framework model. for example if I have model class User in entity framework as

DAL - User Model

[Table("User")]
public class User
{
    public User() { }

    [Key]
    public int UserID { get; set; }

    [StringLength(250)]
    [Required]
    public string FirstName { get; set; }

    [StringLength(250)]
    [Required]
    public string LastName { get; set; }

    [Required]
    public int Age { get; set; }

    [StringLength(250)]
    [Required]
    public string EmailAddress { get; set; }

    public ICollection<UserInGroup> UserInGroup { get; set; }
}

and in business layer I have user class

BLL - User Class

public class User
{
    private string userID;
    private string firstName;
    private string lastName; 
    private int age;
    private string emailAddress;


    public string UserID
    {
        get { return userID; }
        set { userID = value; }
    }

    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }

    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }

    public int Age
    {
        get { return age; }
        set { age = value; }
    }

    public string EmailAddress
    {
        get { return emailAddress; }
        set { emailAddress = value; }
    }

    public void GetAllUser()
    {
        List<App.DAL.Model.User> _user = new List<DAL.Model.User>();

        using (var _uow = new UserManagement_UnitOfWork())
        {

            _user = (from u in _uow.User_Repository.GetAll()
                     select u).ToList();

        }           
    }
}

How I map together and secondly; referring to method GetAllUser(), I still need to use User model class from DAL in order to get all the users from database, where is my current understanding is; each layer should be independent to each other and I have abstraction layer i.e. repository between data access layer and business layer. I am slightly confused of both concept working together. Am I on right track or missing something. also need practical answer on User business layer.

like image 463
K.Z Avatar asked May 19 '15 07:05

K.Z


2 Answers

Your question is more about design/architecture which does not have a 'one-size-fits-all' solution. I can at most share some suggetions and what will I usually do in a fairly typical ASP.NET MVC + Entity Framework stack:

1. Make sure your BLL.User class obeys the Single Responsibility Principle

Your BLL.User class should not concern itself with how to retrieve DAL.User from the database through Entity Framework/Unit of Work. You should simply have another class/layer that will be responsible for that:

public interface IUserRepository
{
    IEnumerable<User> GetAllUsers();
}

Then another class to implement IUserRepository:

public class UserRepository : IUserRepository
{
    private readonly UserManagement_UnitOfWork _unitOfWork;

    public UserRepository(UserManagement_UnitOfWork unitOfWork)
    {
         _unitOfWork = unitOfWork;
    }

    public IEnumerable<User> GetAllUsers()
    {
        return from u in _unitOfWork.User_Repository.GetAll()
               select u;
    }
}

Doing so removes the dependency from your BLL.User to the UserManagment_UnitOfWork class and facilitates testing/mocking (i.e. unit tests can be written to mock an in-memory IUserRepository)

Then from your controller, whenever there is a need to retrieve BLL.Users, you simply inject an instance of IUserRepository to the controller's constructor:

public class UserController
{
    private readonly IUserRepository _userRepository;

    public UserController(IUserRepository userRepository)
    {
         _userRepository = userRepository;
    }

    public ActionResult Index()
    {
        // Simple example using IEnumerable<BLL.User> as the view model
        return View(_userRepository.GetAllUsers().ToList());
    }
}

2. How to map DAL.User to BLL.User

It's actually quite similar to point number 1, you can simply have another interface/class pair:

public interface IUserMapper
{
     BLL.User MapUser(DAL.User);
}

public class UserMapper : IUserMapper
{
    public BLL.User MapUser(DAL.User user)
    {
         return new BLL.User
         {
             FirstName = user.FirstName,
             LastName = user.LastName,
             Age = user.Age
             // etc...
         };
    }
}

Or, if you think writing mapping code is tedious, consider using AutoMapper so that your code becomes Mapper.Map<DAL.User, BLL.User>(user)

Bonus points

  1. You can skip those private fields in BLL.User and convert them to auto-properties
  2. You can add attributes that are derived from ValidationAttribute to aid validation in your ASP.NET MVC application
public class User
{
    public string UserId { get; set; }

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

    public string LastName { get; set; }

    [Range(0, int.MaxValue)]
    public int Age { get; set; }

    [EmailAddress]
    public string EmailAddress { get; set; }
}
like image 58
rexcfnghk Avatar answered Sep 22 '22 16:09

rexcfnghk


You can simply do this by using AutoMapper Install it via Nuget:

PM> Install-Package AutoMapper

and then all you have to do is to config AutoMapper to map similar objects for you.

Mapper.CreateMap<DAL.User, BLL.User>();

You can convert objects anywhere like this :

BLL.User bll_User = Mapper.Map<DAL.User, BLL.User>(dal_user);
like image 44
Iman Nemati Avatar answered Sep 19 '22 16:09

Iman Nemati