简体   繁体   中英

Unable to Map Complex Entity Framework Core using AutoMapper

I'm struggling to figure out how to correctly map an EF core object with inheritance to a DTO using AutoMapper. The correct result I'm looking for is a DTO that has one Training AND ALL the Employees that are registered for it:

Here are the three classes:

public class Training
{
     public Guid Id { get; set; }
     public string Host { get; set; }
     public string Name { get; set; }

     public ICollection<EmployeeTraining> EmployeeTrainings { get; }
}

public class Employee
{
    public Guid Id { get; set; }
    public string Designation { get; set; }

    public ICollection<EmployeeTraining> EmployeeTrainings { get; }
}

public class EmployeeTraining    
{
    public Guid EmployeeId {get; set;}
    public Employee Employee { get; set; }

    public Guid TrainingId { get; set; }
    public Training Training{ get; set; }
}

public class TrainingDTO
{
     public string Host { get; set; }
     public string Name { get; set; }

     public ICollection<EmployeeTraining> EmployeeTrainings { get; }
}

AutoMapper Profile:

public class TrainingProfile: Profile
{
    public TrainingProfile()
    {
        CreateMap<Training, TrainingDto>()
            .ForMember(entity => entity.EmployeeTrainings, opt => opt.MapFrom(model => model));
        CreateMap<TrainingDto, Training>();
    }
}

The code compiles, but when run I get:

[2021-05-03T21:21:49.201Z] Exception: Error mapping types.
[2021-05-03T21:21:49.203Z] Mapping types:
[2021-05-03T21:21:49.204Z] Training -> TrainingDto
[2021-05-03T21:21:49.208Z] AzITSSMaster.API.Entities.Training -> AzITSSMaster.API.Models.TrainingDto
[2021-05-03T21:21:49.209Z] Type Map configuration:
[2021-05-03T21:21:49.209Z] Training -> TrainingDto
[2021-05-03T21:21:49.211Z] AzITSSMaster.API.Entities.Training -> AzITSSMaster.API.Models.TrainingDto
[2021-05-03T21:21:49.212Z] Destination Member:
[2021-05-03T21:21:49.212Z] EmployeeTrainings

Test

    [Fact]
    public void Test1()
    {
        Guid trainingOneGuid = new Guid("5b1c2b4e48c7402a80c3cc796ad49c6b");
        Guid trainingTwoGuid = new Guid("d8663e5f74944f8187396e0de1bea7ee");
        Guid employeeOneGuid = new Guid("5b1c2b4d48c7402a80c3cc796ad49c6b");
        Guid employeeTwoGuid = new Guid("d8663e5e74944f8187396e0de1bea7ee");

        //Create In Memory Database
        var options = new DbContextOptionsBuilder<ITSSAPIContext>()
        .UseInMemoryDatabase(databaseName: "ITSSMaster")
        .Options;

        using (var context = new ITSSAPIContext(options))
        {
            TrainingRepository trepo = new TrainingRepository(context);
            EmployeeRepository erepo = new EmployeeRepository(context);
            EmployeeTrainingRepository etrepo = new EmployeeTrainingRepository(context);

            // Create
            trepo.Create(new Training
            {
                Id = trainingOneGuid,
                Host = "ATS",
                Name = "ATS Test Training 1",
                StartDate = DateTime.Now,
                Facillitator = "Darth Maul",
                StipendAmount = 750,

            });

            trepo.Create(new Training
            {
                Id = trainingTwoGuid,
                Host = "CO",
                Name = "CO Test Training 1",
                StartDate = DateTime.Now,
                Facillitator = "Darth Vader",
                StipendAmount = 0
            });

            erepo.Create(new Employee
            {
                Id = Guid.Parse("5b1c2b4d-48c7-402a-80c3-cc796ad49c6b"),
                OrgDefinedId = 000032615,
                Designation = String.Empty
            });

            erepo.Create(new Employee
            {
                Id = Guid.Parse("d8663e5e-7494-4f81-8739-6e0de1bea7ee"),
                OrgDefinedId = 000012345,
                Designation = "Champion"
            });

            //Training: GetIncluding
            Training training1 = trepo.GetIncluding<Training>(
                trainingOneGuid,
                c => c.EmployeeTrainings);
            Assert.Equal("ATS Test Training 1", training1.Name);

            Training training2 = trepo.GetIncluding<Training>(
                trainingTwoGuid,
                c => c.EmployeeTrainings);
            Assert.Equal("CO Test Training 1", training2.Name);

            //Employee: GetIncluding
            Employee employee1 = erepo.GetIncluding<Employee>(
                employeeOneGuid,
                c => c.EmployeeTrainings);
            Assert.Equal(000032615, employee1.OrgDefinedId);

            Employee employee2 = erepo.GetIncluding<Employee>(
            employeeTwoGuid,
            c => c.EmployeeTrainings);
            Assert.Equal(000012345, employee2.OrgDefinedId);

            //EmployeeTraining:  Add
            etrepo.AddTrainingToEmployee(employee1, training1);
            etrepo.AddTrainingToEmployee(employee2, training1);
            Assert.Equal(2, training1.EmployeeTrainings.Count);

            etrepo.AddTrainingToEmployee(employee1, training2);
            Assert.Equal(1, training2.EmployeeTrainings.Count);

            Assert.Equal(2, employee1.EmployeeTrainings.Count);
            Assert.Equal(1, employee2.EmployeeTrainings.Count);

            //Automapper
            var config1 = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<Training, TrainingDto>()
                    .ForMember(dst => dst.EmployeeTrainings, 
                    opt => opt.MapFrom(model => model.EmployeeTrainings));
            });

            //Using automapper
            var mapper1 = new Mapper(config1);
            var TrainingDto1 = mapper1.Map<TrainingDto>(training1);
            var TrainingDto2 = mapper1.Map<TrainingDto>(training2);
        }
    }

Watch Window

观察窗口

First, check that you've registered your profiles by calling the IServiceCollection extension method AddAutoMapper at application startup:

services.AddAutoMapper();

Then, slightly change your EmployeeTrainings assignment into this:

    CreateMap<Training, TrainingDto>()
        .ForMember(dst => dst.EmployeeTrainings, opt => opt.MapFrom(model => model.EmployeeTrainings));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM