如何在ASP.NET中同时填充嵌套对象?

后端开发 2026-07-09

药物时间表:

public int? UserId { get; set; }
public User User { get; set; } = null!;
public int? MedicationId { get; set; }

public Medication Medication { get; set; } = null!;

public int NumberOfPills { get; set; }
public int Duration { get; set; }

public DateOnly StartDate { get; set; }
public DateOnly? EndDate { get; set; }

public List<ReminderPlanning> ReminderPlannings { get; set; } = new List<ReminderPlanning>();

提醒计划(该时间表的每日安排):

public int Id { get; set; }

public DateOnly reminderDay { get; set; }

public string? dayOfWeek { get; set; }

public int? MedicationScheduleId { get; set; }

public MedicationSchedule MedicationSchedule { get; set; } = new MedicationSchedule();

public List<MedicationReminder> medicationReminders { get; set; } = new List<MedicationReminder>();

药物提醒(你希望收到提醒的小时):

public int Id { get; set; }
public int? ReminderPlanningId { get; set; }
public ReminderPlanning? ReminderPlanning { get; set; }

public TimeOnly ReminderHour { get; set; }

我采用了这种架构,让用户可以动态选择提醒次数。

起初我想做的是在每次创建父对象时使用一个循环:

public async Task<MedicationSchedule> CreateMedicationScheduleAsync(MedicationSchedule medicationScheduleModel)
{     
    medicationScheduleModel.EndDate = medicationScheduleModel.StartDate.AddDays(medicationScheduleModel.Duration);

    return await _scheduleRepository.CreateMedicationScheduleAsync(medicationScheduleModel);
    // for (int i = 0; i <medicationScheduleModel.duration ; i++) { 
    // call create planning, and inside that service I would create the reminder 
    //     for (int i = 0; i <medicationPlanningModel.MedicationSchedule.numberofpills; i++) {
    // Obviously the order is messed up}
    // }
}

但提醒小时并未随时间表一起发送。这迫使我创建一个包含空计划项的时间表,并使用一个单独的POST请求来填充这些表。

编辑:DTO

using backend.Models;

namespace backend.Dtos.MedicationScheduleDtos
{
    public class CreateMedicationScheduleDto
    {
        public int? UserId { get; set; }
        public int? MedicationId { get; set; }

        public int NumberOfPills { get; set; }
        public int Duration { get; set; }

        public DateOnly StartDate { get; set; }

        public List<CreateReminderPlanningDto> ReminderPlannings { get; set; }
    }
}

控制器中的POST方法:

[HttpPost]
public async Task<IActionResult> CreateSchedule([FromBody] CreateMedicationScheduleDto medicationScheduleDto)
{
    var medicationScheduleModel = medicationScheduleDto.ToMedicationScheduleFromCreateDto();
    await _scheduleService.CreateMedicationScheduleAsync(medicationScheduleModel);

    return CreatedAtAction(nameof(GetScheduleById), new { id = medicationScheduleModel.Id }, medicationScheduleModel.ToMedicationScheduleDto());
}

解决方案

可以在一个单一的POST请求中填充三层结构(MedicationSchedule → ReminderPlanning → MedicationReminder)。当你创建一个对象图并调用 SaveChanges() 时,Entity Framework会为你处理好这一切。

步骤1:在控制器中接收嵌套的JSON

确保你的API支持整个嵌套的数据结构:

[HttpPost]
public async Task<IActionResult> CreateMedicationSchedule([FromBody] MedicationSchedule medicationScheduleModel)
{
    if (!ModelState.IsValid) return BadRequest(ModelState);

    var result = await _scheduleService.CreateWithRemindersAsync(medicationScheduleModel);
    return CreatedAtAction(nameof(GetSchedule), new { id = result.Id }, result);
}

示例JSON负载 客户端应发送:

{
  "userId": 1,
  "medicationId": 5,
  "numberOfPills": 2,
  "duration": 7,
  "startDate": "2026-05-01",
  "reminderPlannings": [
    {
      "reminderDay": "2026-05-01",
      "dayOfWeek": "Thursday",
      "medicationReminders": [
        { "reminderHour": "08:00" },
        { "reminderHour": "20:00" }
      ]
    }
  ]
}

步骤2:在你的服务中构建并保存整个对象图

public async Task<MedicationSchedule> CreateWithRemindersAsync(MedicationSchedule model)
{
    // 1. Calculate end date
    model.EndDate = model.StartDate.AddDays(model.Duration);

    // 2. Auto-generate daily ReminderPlannings if not provided
    if (model.ReminderPlannings == null || !model.ReminderPlannings.Any())
    {
        for (int i = 0; i < model.Duration; i++)
        {
            var day = model.StartDate.AddDays(i);
            model.ReminderPlannings.Add(new ReminderPlanning
            {
                reminderDay = day,
                dayOfWeek = day.DayOfWeek.ToString(),
                medicationReminders = new List<MedicationReminder>()
            });
        }
    }

    // 3. Link each planning back to the schedule (EF needs this)
    foreach (var planning in model.ReminderPlannings)
    {
        planning.MedicationSchedule = model;
    }

    // 4. Add the root entity - EF Core tracks the entire graph
    await _context.MedicationSchedules.AddAsync(model);

    // 5. ONE SaveChanges() inserts everything in a single transaction [[8]][[16]]
    await _context.SaveChangesAsync();

    return model;
}

步骤3:验证你的实体配置

确保你的关系在 OnModelCreating 中正确设置:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MedicationSchedule>()
        .HasMany(s => s.ReminderPlannings)
        .WithOne(p => p.MedicationSchedule)
        .HasForeignKey(p => p.MedicationScheduleId)
        .OnDelete(DeleteBehavior.Cascade); // Optional: auto-delete children if parent is deleted

    modelBuilder.Entity<ReminderPlanning>()
        .HasMany(p => p.medicationReminders)
        .WithOne(r => r.ReminderPlanning)
        .HasForeignKey(r => r.ReminderPlanningId)
        .OnDelete(DeleteBehavior.Cascade);
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章