EF如何更新相关记录?

时间:2018-04-29 07:09:20

标签: c# entity-framework-core automapper

当我更新相关记录时,我注意到更新后,主键被重新分配。后者是long中的RecordId数据类型(PartnersRegistry中的示例await unitOfWork.CompleteAsync();),我注意到保存更改后其值已更改。看起来EF正在删除旧的实体对象并添加新的实体对象,而不仅仅是更新更改(下例中的Primary Key)。

我有两个问题:

  1. 这是正常行为吗?
  2. 这里用来避免播种的最佳[Table("PatientsRegistry")] public class PatientRegistry { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] [Display(Name = "Record Id")] public long RecordId { get; set; } [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] [Display(Name = "Patient File Number")] public long PatientFileId { get; set; } public DateTimeOffset DateCreated { get; set; } [Timestamp] public byte[] RowVersion { get; set; } public virtual ICollection<PartnerRegistry> Partners { get; set; } } 是什么?
  3. 我发布相关代码:

    实体1

    [Table("PartnersRegistry")]
    public class PartnerRegistry
    {   
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long RecordId { get; set; }
    
        public long PatientFileId { get; set; }
        public long PartnerFileId { get; set; }
        [JsonIgnore]
        public virtual PatientRegistry PatientsRegistry { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime? EndDate { get; set; }    
    }
    

    相关实体

    [HttpPut]
    public async Task<IActionResult> UpdatePatient(long fileId, [FromBody] SavePatientsRegistryViewModel model)
    {
        SuccessResponse response = new SuccessResponse();
    
        if (!ModelState.IsValid)
            return StatusCode(400, StaticHandlers.FormatErrorResponse(ModelState));
    
        PatientRegistry patient = await repository.GetPatient(fileId);
        if (patient == null)
        {
            ModelState.AddModelError(string.Empty, "The patient does not exist in the database");
            return StatusCode(404, StaticHandlers.FormatErrorResponse(ModelState));
        }
        model.PatientFileId = patient.PatientFileId;
        PatientRegistry modelPatientRegistryData = mapper.Map<SavePatientsRegistryViewModel, PatientRegistry>(model, patient);
    
        await unitOfWork.CompleteAsync();
        response.SuccessMessage = patient.FirstName + " " + patient.LastName + " has been updated successfully!";
        response.DataResponse = patient.PatientFileId;
        return StatusCode(200, response);
    }
    

    在我的控制器中

    public class SavePatientsRegistryViewModel
    {
        public long PatientFileId { get; set; }
        public ICollection<SavePartnerRegistryViewModel> Partners { get; set; }
        public OnlineAccountViewModel OnlineAccount { get; set; }
        public SavePatientsRegistryViewModel()
        {
            Partners = new Collection<SavePartnerRegistryViewModel>();
        }
    }
    
    public class SavePartnerRegistryViewModel
    {
        public string RecordId { get; set; }
        public long PatientFileId { get; set; }
        public long PartnerFileId { get; set; }
        public string StartDate { get; set; }
        public string EndDate { get; set; }
    }
    

    根据以下评论,我正在扩展相关代码。

    这些是控制器使用的视图模型:

    CreateMap<SavePatientsRegistryViewModel, PatientRegistry>()
        .ForMember(pr => pr.RecordId, opt => opt.Ignore())
        .ForMember(pr => pr.PatientFileId, opt => opt.Ignore())
        .ForMember(pr => pr.UserId, opt => opt.Ignore())
        .ForMember(pr => pr.Partners, opt => opt.MapFrom(c => c.Partners))
        .ForMember(pr => pr.User, opt => opt.MapFrom(c => c.OnlineAccount));
    
    CreateMap<SavePartnerRegistryViewModel, PartnerRegistry>()
        .ForMember(pr => pr.RecordId, opt => opt.Ignore())
        .ForMember(pr => pr.PatientFileId, opt => opt.Ignore())
        .ForMember(pr => pr.PatientFileId, opt => opt.MapFrom(s => s.PatientFileId))
        .ForMember(pr => pr.PartnerFileId, opt => opt.MapFrom(s => s.PartnerFileId))
        .ForMember(pr => pr.StartDate, opt => opt.MapFrom(s => s.StartDate))
        .ForMember(pr => pr.EndDate, opt => opt.MapFrom(s => s.EndDate));
    

    我的映射配置文件是:

    await unitOfWork.CompleteAsync();

    基本上,我在控制器中的更新方法中执行的操作如下:

    1. 我通过从Dbcontext调用来检查患者是否存在。

    2. 我将视图模型映射到实体。

    3. 映射后,值会发生变化,我会调用await context.SaveChangesAsync();,这基本上是PartnerRegistry

    4. 我的问题出在相关表格中(RecordId)。保存更改后,作为PK的列RecordId将获得新值。现在,EF没有确定更新此列,即使我尝试,我也会收到错误消息,说明自动生成后无法在此字段中插入值!

      { "patientFileId": 1111, "partners": [ { "recordId": **5**, "patientFileId": 1111, "partnerFileId": 2222, "startDate": "1/1/90 12:00:00 AM", "endDate": "1/1/00 12:00:00 AM", "patientName": null } ] } 更改其值的唯一方法是插入,删除并重新插入整个记录。

      以下示例。

      更新之前:

      {
          "patientFileId": 1111,
          "partners": [
              {
                  "recordId": **6**,
                  "patientFileId": 1111,
                  "partnerFileId": 2222,
                  "startDate": "1/1/90 12:00:00 AM",
                  "endDate": "1/1/00 12:00:00 AM",
                  "patientName": null
              }
          ]
      }
      

      更新后

      Partners

      更新

      调试后,我发现映射后重新初始化了PatientRegistry patient = await repository.GetPatient(fileId);集合!

      Partners

      此处的ICollection集合与上下文中的相同。但是,在映射之后,由于某种原因,整个PatientRegistry modelPatientRegistryData = mapper.Map<SavePatientsRegistryViewModel, PatientRegistry>(model, patient);被重新初始化。具体来说:

      public class AudioPlayer { Long currentFrame; Clip clip; // current status of clip String status; AudioInputStream musicInputStream; // constructor to initialize streams and clip public AudioPlayer(Schedule schedule,List<File> files) throws UnsupportedAudioFileException, IOException, LineUnavailableException { // create AudioInputStream object musicInputStream = AudioSystem.getAudioInputStream(files.get(0).getAbsoluteFile()); // create clip reference clip = AudioSystem.getClip(); // open audioInputStream to the clip clip.open(musicInputStream); clip.loop(Clip.LOOP_CONTINUOUSLY); } }

1 个答案:

答案 0 :(得分:0)

正如@smit所说,AutoMapper在映射后创建了一个新集合,而不是修改现有集合。类似的问题描述为here

我的解决方法如下,

我忽略了集合的映射,然后在这里手动评估记录操作,(插入/更新/删除)

// CreateMap<SavePartnerRegistryViewModel, PartnerRegistry> ();不再需要。

        CreateMap<SavePatientsRegistryViewModel, PatientRegistry> ()
            .ForMember (d => d.RecordId, opt => opt.Ignore ())
            .ForMember (d => d.PatientFileId, opt => opt.Ignore ())
            .ForMember (d => d.UserId, opt => opt.Ignore ())
            .ForMember (d => d.Partners, opt => opt.Ignore ())
            .ForMember (d => d.User, opt => opt.MapFrom (s => s.OnlineAccount))
            .AfterMap ((s, d) => {
// check if context object is included in the model? if not prime for delete.
                foreach (PartnerRegistry partner in d.Partners.ToList ()) {
                    SavePartnerRegistryViewModel modelPartner = s.Partners.SingleOrDefault (c => c.PatientFileId == partner.PatientFileId && c.PartnerFileId == partner.PartnerFileId);
                    if (!s.Partners.Contains (modelPartner)) {
                        d.Partners.Remove (partner);
                    }
                }
// check if model object(s) is/are included in the context? 
                foreach (SavePartnerRegistryViewModel modelPartner in s.Partners) {
                    PartnerRegistry partner = d.Partners.SingleOrDefault (c => c.PatientFileId == modelPartner.PatientFileId && c.PartnerFileId == modelPartner.PartnerFileId);
// if yes, prime for update
                    if (d.Partners.Contains (partner)) {
                        partner.PartnerFileId = modelPartner.PartnerFileId;
                        partner.StartDate = DateTime.Parse (modelPartner.StartDate);
                        partner.EndDate = string.IsNullOrWhiteSpace (modelPartner.EndDate) ? (DateTime?) null : DateTime.Parse (modelPartner.EndDate);
                    } else {
// if Not, prime for insert
                        d.Partners.Add (
                            new PartnerRegistry {
                                PatientFileId = modelPartner.PatientFileId,
                                    PartnerFileId = modelPartner.PartnerFileId,
                                    StartDate = DateTime.Parse (modelPartner.StartDate),
                                    EndDate = string.IsNullOrWhiteSpace (modelPartner.EndDate) ? (DateTime?) null : DateTime.Parse (modelPartner.EndDate)
                            }
                        );
                    }
                }
            });