EF Core Многие ко многим, использующие Automapper, возвращают цикл в API Resource - PullRequest
0 голосов
/ 01 мая 2018

Я использую .net Core с EF2 и хочу установить это отношение «многие ко многим». У любого доктора может быть много назначений и наоборот. Также я хочу реализовать отображение Automapper сверху.

Структура модели высокого уровня

**Doctor**
 - Id
 - Name
 - Appointments
**Appointment**
 - Id
 - Name
 - Category
 - Doctors

Модель врачей

[Table("Doctors")]
public class Doctor
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<DoctorAppointment> Appointments { get; set; }
    public Doctor()
    {
        Appointments = new Collection<DoctorAppointment>();
    }
}

Назначения Модель

[Table("Appointments")]
public class Appointment
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
    public ICollection<DoctorAppointment> Doctors { get; set; }
    public Appointment()
    {
        Doctors = new Collection<DoctorAppointment>();
    }
}

Таблица привязки многих ко многим врачам и назначениям

[Table("DoctorAppointments")]
public class DoctorAppointment
{
    public int DoctorId { get; set; }
    public int AppointmentId { get; set; }
    public Doctor Doctor { get; set; }
    public Appointment Appointment { get; set; }  
}

контекст БД

public class MyDocDbContext : DbContext
{
    public DbSet<Appointment> Appointments { get; set; }
    public DbSet<Doctor> Doctors { get; set; }

    public MyDocDbContext(DbContextOptions<MyDocDbContext> options) 
      : base(options)
    {
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder) 
    {
        modelBuilder.Entity<DoctorAppointment>().HasKey(da => 
          new { da.DoctorId, da.AppointmentId });

        modelBuilder.Entity<DoctorAppointment>()
            .HasOne(da => da.Doctor)
            .WithMany(p => p.Appointments)
            .HasForeignKey(pt => pt.DoctorId);

        modelBuilder.Entity<DoctorAppointment>()
            .HasOne(pt => pt.Appointment)
            .WithMany(t => t.Doctors)
            .HasForeignKey(pt => pt.AppointmentId);
    }
}

Врачи и назначение Контроллеры :

    [HttpGet("appointment/{id}")]
    public async Task<IActionResult> GetAppointment(int id)
    {
        var app =  await context.Appointments
          .Include(a => a.Doctors)
          .ThenInclude(da => da.Doctor)        
          .SingleOrDefaultAsync(a => a.Id == id);
        return Ok(app);
    }

    [HttpGet("doctor/{id}")]
    public async Task<IActionResult> GetDoctor(int id)
    {
      var doc =  await context.Doctors   
        .Include(d => d.Appointments)
        .ThenInclude(da => da.Appointment)
        .SingleOrDefaultAsync(v => v.Id == id);
        return Ok(doc);
    }

Теперь реализуем Automapper Resource Mapping ...

До этого момента все работает нормально, так как при получении этих двух сущностей он возвращает все отношения. Проблема возникает при использовании Automapper для сопоставления домена с ресурсом API. Использование следующих ресурсов сопоставления:

DoctorResource

public class DoctorResource
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<AppointmentResource> Appointments { get; set; }
    public DoctorResource()
    {
        Appointments = new Collection<AppointmentResource>();
    }
}

AppointmentResource

public class AppointmentResource
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
    public ICollection<DoctorResource> Doctors { get; set; }
    public AppointmentResource()
    {
        Doctors = new Collection<DoctorResource>();
    }

}

Наконец, отображение выглядит следующим образом:

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        // Domain to API Resource

        CreateMap<Doctor, DoctorResource>()
             .ForMember(dr => dr.Appointments, opt => opt
                 .MapFrom(d => d.Appointments
                 .Select(y => y.Appointment)
                 .ToList()));

        CreateMap<Appointment, AppointmentResource>()
            .ForMember(dr => dr.Doctors, opt => opt
                .MapFrom(d => d.Doctors
                .Select(y => y.Doctor)
                .ToList()));
    }
}

Итак, когда НЕ использует ресурсы отображения, результат JSON будет таким (желаемым):

**http://localhost:5000/api/appointment/1**

{
"id": 1,
"name": "Personal Trainer",
"category": "Fitness",
"doctors": [
    {
        "doctorId": 2027,
        "appointmentId": 1,
        "doctor": {
            "id": 2027,
            "name": "Dr. Cunha",
            "appointments": [],
        }
    },
    {
        "doctorId": 2028,
        "appointmentId": 1,
        "doctor": {
            "id": 2028,
            "name": "Dr. Gouveia",
            "appointments": [],
        }
    },
    {
        "doctorId": 2029,
        "appointmentId": 1,
        "doctor": {
            "id": 2029,
            "name": "Dr. Tiago",
            "appointments": [],
        }
    }
  ]
}

Однако при использовании Automapper для сопоставления ответа API он снова расширяет категорию «Назначения» и «Доктора» и т. Д. ...

**http://localhost:5000/api/appointment/1**

{
"id": 1,
"name": "Personal Trainer",
"category": "Fitness",
"doctors": [
    {
        "id": 2027,
        "name": "Dr. Cunha",
        "appointments": [
            {
                "id": 1,
                "name": "Personal Trainer",
                "category": "Fitness",
                "doctors": [
                    {
                        "id": 2028,
                        "name": "Dr. Gouveia",
                        "appointments": [
                            {
                                "id": 1,
                                "name": "Personal Trainer",
                                "category": "Fitness",
                                "doctors": [
                                     { ....
                                      and so on...

Однако по какой-то неизвестной мне причине Doctor Controller возвращает желаемый результат.

Извините за длинный пост, но я не смог бы дать вам ясную картину, не разоблачив все это.

Приветствия

1 Ответ

0 голосов
/ 19 декабря 2018

Я предполагаю, что ваш MappingProfile должен измениться следующим образом:

public MappingProfile()
{
    // Domain to API Resource

    CreateMap<Doctor, DoctorResource>()
         .ForMember(dr => dr.Appointments, opt => opt
             .MapFrom(d => d.DoctorAppointment
             .Select(y => y.Appointment)
             .ToList()));

    CreateMap<Appointment, AppointmentResource>()
        .ForMember(dr => dr.Doctors, opt => opt
            .MapFrom(d => d.DoctorAppointment
            .Select(y => y.Doctor)
            .ToList()));
}

Вместо MapFrom (d => d.Doctors), а также MapFrom (d => d.Appointments) замените их на MapFrom (d => d.DoctorAppointment)

это должно быть работа.

...