简体   繁体   English

使用Automapper的EF Core多对多返回API资源上的循环

[英]EF Core Many to Many using Automapper returns loop on API Resource

I'm using .net Core with EF2 and I want to setup this Many to Many relationship. 我将.net Core与EF2结合使用,并且我想设置这种多对多关系。 Any Doctor can have many Appointments and vice versa. 任何医生都可以有许多约会,反之亦然。 Also I want to implement Automapper mapping on top. 我也想在上面实现Automapper映射。

High Level Model Structure 高级模型结构

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

Doctors Model 医生模型

[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>();
    }
}

Appointments Model 预约模式

[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>();
    }
}

Many to Many Doctors-Appointments Linking Table 多对多医生预约链接表

[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; }  
}

DB context 数据库上下文

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);
    }
}

Doctors and Appointment Controllers : 医生和预约控制器

    [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);
    }

Now implementing Automapper Resource Mapping ... 现在实现Automapper资源映射 ...

Until this point everything works fine, as when fetching on of those two entities it returns all the relations. 到现在为止,一切工作正常,因为在获取这两个实体时,它将返回所有关系。 The problem comes when using Automapper to map the Domain to API Resource. 使用Automapper将域映射到API资源时出现问题。 Using the following mapping resources: 使用以下映射资源:

DoctorResource 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>();
    }

}

Finally, the mapping is the following: 最后, 映射如下:

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()));
    }
}

So, when NOT using the mapping resources, the JSON result is this (the wanted one): 因此,当使用映射资源时,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": [],
        }
    }
  ]
}

However when using Automapper to map the API response it expands the Appointments category and the the Doctors again, and so on... 但是, 当使用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...

However for some unknown reason to me the Doctor Controller returns the desired output. 但是由于某种未知的原因, 医生控制器会返回所需的输出。

Sorry about the lengthy post, but I couldn't provide you with a clear picture without exposing the whole thing. 很抱歉,冗长的帖子,但是如果不公开整个内容,我无法为您提供清晰的图片。

Cheers 干杯

I assume that you'r MappingProfile should be change like bellow: 我假设您的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()));
}

Instead of MapFrom(d => d.Doctors) and also MapFrom(d => d.Appointments) replace them with MapFrom(d => d.DoctorAppointment) 除了使用MapFrom(d => d.DoctorAppointment)代替MapFrom(d => d.Doctors)之外,还使用MapFrom(d => d.Appointments)替换它们。

it should be work. 它应该工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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