Eduardo Spaki
Eduardo Spaki

Reputation: 1188

Automapper is losing reference

How to setup automapper to the next scenario works properly?

using AutoMapper;
using System;
using System.Collections.Generic;

namespace ConsoleApplication5
{
    public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Company
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<Employee> Employees { get; set; }
    }

    public class Country
    {
        public List<Company> Companies { get; set; }
        public List<Employee> Employees { get; set; }
    }

    public class EmployeeDto
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class CompanyDto
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<EmployeeDto> Employees { get; set; }
    }

    public class CountryDto
    {
        public List<CompanyDto> Companies { get; set; }
        public List<EmployeeDto> Employees { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // mapper set up
            Mapper.Initialize((cfg) =>
            {
                cfg.CreateMap<Country, CountryDto>();
                cfg.CreateMap<Company, CompanyDto>();
                cfg.CreateMap<Employee, EmployeeDto>();
            });

            // data
            var company = new Company
            {
                Id = 1,
                Name = "Blah",
                Employees = new List<Employee> {
                    new Employee { Id = 1, Name = "John" },
                    new Employee { Id = 2, Name = "Mary" },
                }
            };

            var country = new Country { Companies = new List<Company> { company } };
            country.Employees = company.Employees;

            // mapping
            var dto = Mapper.Map<CountryDto>(country);

            //print
            dto.Companies[0].Employees[0].Id = 100;
            Console.WriteLine("{0} - {1}", dto.Companies[0].Employees[0].Id, dto.Employees[0].Id); // should be the same
            Console.WriteLine(dto.Companies[0].Employees[0].Id == dto.Employees[0].Id); // should be true

            Console.WriteLine("End");
            Console.ReadLine();
        }
    }
}

basically I want to change some property in my first DTO list and that changes should reflect to the same list, but in another porperty.

ps: when I'm using my domain entities is working fine!

Upvotes: 4

Views: 935

Answers (1)

ironstone13
ironstone13

Reputation: 3453

This is not a problem of automapper, but rather the design of your classes. Automapper has no idea that CountryDto.Employees and CountryDto.Companies.Employees are meant to be the same, furthermore, developers reading your code will know that as well - because of the way the classes are designed. Automapper just creates a new List<EmployeeDto>for every List<Employee> The fact that the collections match in domain entity is because you set one collection reference to be equal to the other country.Employees = company.Employees; However, they are NOT equal by design, they are two different references. They are only equal because of how they are initialized.

What is the purpose of this design?

If you would like to list all employees of all companies on a country object - you have to define a calculated property (or better, a method) that would aggregate the fields from countries, for example using select many

However, putting a calculation property on DTO is not a good design choice. Please describe more what you are trying to achieve, so I can suggest a better design.

Upvotes: 2

Related Questions