Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manually mapping DTO WITHOUT using AutoMapper?

I'm learning C#.NET Core and trying to create DTO mapping without using AutoMapper as I'm working on a small project alone and want to understand fundamental before using extra packages, surpringly I could not easily find answer at stackoverflow.com or I may use wrong keyword searching.

BTW, below is my code which I successfully map to EmployeeForShortDto under GetEmployee method. Unfortunately, I don't how to map it under GetAllEmployee just because the return data is a collection, not a single record. Please advice.

EmployeeController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NetCoreWebApplication1.Dto;
using NetCoreWebApplication1.Repository;
using NetCoreWebApplication1.Other;

namespace NetCoreWebApplication1.Controller
{
    [Route("api/[controller]")]
    [ApiController]
    public class EmployeeController : ControllerBase
    {
        private readonly IMasterRepository _repo;

        public EmployeeController(IMasterRepository repo)
        {
            _repo = repo;
        }

        [HttpGet("{id}")]
        public async Task<IActionResult> GetEmployee(int id)
        {
            var data = await _repo.GetEmployee(id);
            if (data == null) return NotFound();
            var dataDto = new EmployeeForShortDto()
            {
                Id = data.Id,
                EmpCode = data.EmpCode,
                Fname = data.Fname,
                Lname = data.Lname,
                Age = NetCoreWebApplication1.Other.Extension.CalcAge(data.DateBirth)
            };

            return Ok(dataDto);
        }

        [HttpGet]
        public async Task<IActionResult> GetAllEmployee()
        {
            var data = await _repo.GetAllEmployee();
            return Ok(data);
        }

    }
}

MasterRepository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using NetCoreWebApplication1.Models;

namespace NetCoreWebApplication1.Repository
{
    public class MasterRepository : IMasterRepository
    {
        private readonly PrDbContext _context;

        public MasterRepository(PrDbContext context)
        {
            _context = context;
        }


        // Employee
        public async Task<List<Employee>> GetAllEmployee()
        {
            var data = await _context.Employee.ToListAsync();
            return data;
        }

        public async Task<Employee> GetEmployee(int id)
        {
            var data = await _context.Employee.FirstOrDefaultAsync(x => x.Id == id);
            return data;
        }

        // Generic methods
        public void Add<T>(T entity) where T : class
        {
            _context.Add(entity);
        }

        public void Delete<T>(T entity) where T : class
        {
            _context.Remove(entity);
        }

        public async Task<bool> SaveAll()
        {
            return await _context.SaveChangesAsync() > 0;
        }
    }
}
like image 527
user10268539 Avatar asked Aug 24 '18 09:08

user10268539


2 Answers

You can use an extension method to map from your entity type to your DTO type.

public static EmployeeForShortDto ToDto(this Employee employee)
{
    if (employee != null)
    {
        return new EmployeeForShortDto
        {
            Id = employee.Id,
            EmpCode = employee.EmpCode,
            Fname = employee.Fname,
            Lname = employee.Lname,
            Age = NetCoreWebApplication1.Other.Extension.CalcAge(employee.DateBirth)
        };
    }

    return null;
}

And then use where needed.

[HttpGet("{id}")]
public async Task<IActionResult> GetEmployee(int id)
{
    var data = await _repo.GetEmployee(id);

    if (data == null) 
    {
        return NotFound();
    }

    return Ok(data.ToDto());
}

[HttpGet]
public async Task<IActionResult> GetAllEmployee()
{
    var data = await _repo.GetAllEmployee();

    return Ok(data.Select(x => x.ToDto()));
}
like image 56
Brad Avatar answered Sep 19 '22 01:09

Brad


thank you for all responses, all are very useful to me. Finally, I end up with solution from @Brad. I also learned how to make a reverse mapping from DTO to a class before adding a record to the database.

I put my code below in case someone want to see. Any comments/suggestions are more than welcome. Thank you.

Extension.cs

using NetCoreWebApplication1.Dto;
using NetCoreWebApplication1.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace NetCoreWebApplication1.Other
{
    public static class Extension
    {
        public static EmployeeForShortDto MapToEmployeeForShortDto(this Employee emp)
        {
            if (emp != null)
            {
                return new EmployeeForShortDto
                {
                    Id = emp.Id,
                    EmpCode = emp.EmpCode,
                    Fname = emp.Fname,
                    Lname = emp.Lname,
                    Age = emp.DateBirth.CalcAge()
                };
            }

            return null;
        }

        public static EmployeeForListDto MapToEmployeeForListDto(this Employee emp)
        {
            if (emp != null)
            {
                return new EmployeeForListDto
                {
                    Id = emp.Id,
                    EmpCode = emp.EmpCode,
                    Fname = emp.Fname,
                    Lname = emp.Lname,
                    Age = emp.DateBirth.CalcAge(),
                    EntityCode = emp.EntityCode,
                    IsActive = emp.IsActive
                };
            }

            return null;
        }

        public static Employee MapFromEmployeeForAddDto(this EmployeeForAddDto emp)
        {
            if (emp != null)
            {
                return new Employee
                {
                    EmpCode = emp.EmpCode,
                    Fname = emp.Fname,
                    Lname = emp.Lname,
                    IdCard = emp.IdCard,
                    IsActive = 1
                };
            }

            return null;
        }

        public static int CalcAge(this DateTime? dateBirth)
        {
            if (dateBirth.HasValue)
            {
                var age = DateTime.Today.Year - dateBirth.Value.Year;
                if (dateBirth.Value.AddYears(age) > DateTime.Today) age--;
                return age;
            }
            else
            {
                return 0;
            }
        }
    }
}

MasterRepository.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using NetCoreWebApplication1.Dto;
using NetCoreWebApplication1.Models;

namespace NetCoreWebApplication1.Repository
{
    public class MasterRepository : IMasterRepository
    {
        private readonly PrDbContext _context;

        public MasterRepository(PrDbContext context)
        {
            _context = context;
        }


        // Employee
        public async Task<List<Employee>> GetAllEmployee()
        {
            var data = await _context.Employee.ToListAsync();
            return data;
        }

        public async Task<Employee> GetEmployee(int id)
        {
            var data = await _context.Employee.FirstOrDefaultAsync(x => x.Id == id);
            return data;
        }

        public async Task<Employee> AddEmployee(Employee data)
        {
            await _context.Employee.AddAsync(data);
            await _context.SaveChangesAsync();
            return data;
        }

        public async Task<bool> EmployeeExists(string entityCode, string empCode)
        {
            if (await _context.Employee.AnyAsync(x =>
                x.EntityCode == entityCode &&
                x.EmpCode == empCode))
                return true;

            return false;
        }

        // Generic methods
        public void Add<T>(T entity) where T : class
        {
            _context.Add(entity);
        }

        public void Delete<T>(T entity) where T : class
        {
            _context.Remove(entity);
        }

        public async Task<bool> SaveAll()
        {
            return await _context.SaveChangesAsync() > 0;
        }
    }
}

EmployeeController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NetCoreWebApplication1.Dto;
using NetCoreWebApplication1.Repository;
using NetCoreWebApplication1.Other;
using NetCoreWebApplication1.Models;

namespace NetCoreWebApplication1.Controller
{
    [Route("api/[controller]")]
    [ApiController]
    public class EmployeeController : ControllerBase
    {
        private readonly IMasterRepository _repo;

        public EmployeeController(IMasterRepository repo)
        {
            _repo = repo;
        }

        [HttpPost("add")]
        public async Task<IActionResult> AddEmployee(EmployeeForAddDto emp)
        {
            if (await _repo.EmployeeExists(emp.EntityCode, emp.EmpCode))
                ModelState.AddModelError("Employee", "Employee is duplicate (EntityCode + EmpCode)");

            if (!ModelState.IsValid)
                return BadRequest(ModelState);

            Employee employeeToAdd = emp.MapFromEmployeeForAddDto();

            await _repo.AddEmployee(employeeToAdd);

            return StatusCode(201);
        }


        [HttpGet("{id}")]
        public async Task<IActionResult> GetEmployee(int id)
        {
            var data = await _repo.GetEmployee(id);

            if (data == null) return NotFound();

            return Ok(data.MapToEmployeeForShortDto());
        }

        [HttpGet]
        public async Task<IActionResult> GetAllEmployee()
        {
            var data = await _repo.GetAllEmployee();

            //var dataDto = data.Select(x => x.MapToEmployeeForShortDto());
            var dataDto = data.Select(x => x.MapToEmployeeForListDto());

            return Ok(dataDto);
        }

    }
}
like image 41
user10268539 Avatar answered Sep 19 '22 01:09

user10268539