HTTP PUT 在 Angular 应用程序中创建而不是更新

HTTP PUT is creating instead of updating in Angular app

我正在使用 Angular 开发一个简单的 CRUD 应用程序,当我提交我的表单更新 table 的一个元素时,它会创建另一个元素而不是更新相同的元素。怎么了?

服务Class:

export class EquipmentsService {
  url = "https://localhost:5001/api/Equipment";
  constructor(private http: HttpClient) { }

   Getall(): Observable<Equipments[]>{
    return this.http.get<Equipments[]>(this.url);
  }


  GetWithId(EquipmentsID: number): Observable<Equipments>
  {
    const Url = `${this.url}/${EquipmentsID}`;
    return this.http.get<Equipments>(Url);
  }
  PostEquipment(equipment: Equipments ): Observable<any>{
    return this.http.post<Equipments>(this.url, equipment, httpOptions);
  }
  PutEquipment(equipment: Equipments): Observable<any>{
    return this.http.put<Equipments>(this.url, equipment,httpOptions);
  }

  DeleteEquipment(equipmentId: number): Observable<any>
  {
    const Url = `${this.url}/${equipmentId}`;
    return this.http.delete<Number>(Url, httpOptions);
  }
}

对话框组件:

export class DialogFormUpdateComponent implements OnInit {

  public titleForm!: string;
  formG!: FormGroup;
  equip!: Equipments;
  id!: number;


  constructor(public dialogRef: MatDialogRef<DialogFormUpdateComponent>, private fb: FormBuilder,
    private EquipmentService: EquipmentsService) {

  }

  ngOnInit(): void {

      console.log(this.id); // It's receiving Id value

      this.EquipmentService.GetWithId(this.id).subscribe(result => {
        this.titleForm = "Update Equipment";
        this.formG = this.fb.group({
          name: [result.name, [Validators.required]],
          serialNumber: [result.serialNumber, [Validators.required]],
          voltage: [result.voltage, [Validators.required]],
          electricCurrent: [result.electricCurrent, [Validators.required]],
          oil: [result.oil, [Validators.required]],
          date: [result.date, [Validators.required]],
        });
      });

  }

  public SendFormUpdate(): void {

    let newDate: moment.Moment = moment.utc(this.formG.value.date).local();
    this.formG.value.date = newDate.format("YYYY-MM-DD");
    const equipment: Equipments = this.formG.value;

    this.EquipmentService.PutEquipment(equipment).subscribe(result => {

      alert("Equipment was updated with success");
      this.formG.reset();
      this.dialogRef.close();
    })
  }

  Cancel() {

    this.dialogRef.close();
    this.formG.reset();

  }
}

设备组件:

export class EquipmentsComponent implements OnInit {
  ELEMENT_DATA!: Equipments[];
  form: any;
  titleForm!: string;
  displayedColumns: string[] = ['name', 'serialNumber', 'voltage', 'electricCurrent', 'oil', 'date', 'actions'];
  @Output() equipID: EventEmitter<number>= new EventEmitter<number>();


  public dataSource = new MatTableDataSource<Equipments>(this.ELEMENT_DATA);

  constructor(private EquipmentService: EquipmentsService, public dialog: MatDialog,
    public DialogUpate: MatDialog, public DialogComponentUpdate: DialogFormUpdateComponent) { }

  ngOnInit(): void {

    //getall on start
      this.EquipmentService.Getall().subscribe(result => {
      this.dataSource.data = result as Equipments[];
    });
  }

  //Open Create Form
  NewEquipemnt(): void {
    const dialogRef = this.dialog.open(DialogFormComponent,{
      minWidth: '300px', disableClose: true

    });

    dialogRef.afterClosed().subscribe(result => {
      console.log('The dialog was closed');
      //get all
      this.EquipmentService.Getall().subscribe(result => {
        this.dataSource.data = result as Equipments[];
        });
    });
  }

  //Open Update Form
  public UpdateEquipment(EquipId:  number): void
  {

    const dialogRef = this.DialogUpate.open(DialogFormUpdateComponent,{
      minWidth: '300px', disableClose: true,
    });

    dialogRef.componentInstance.id = EquipId;
    dialogRef.afterClosed().subscribe(result => {
      console.log('The dialog was closed');
        //get all
        this.EquipmentService.Getall().subscribe(result => {
        this.dataSource.data = result as Equipments[];
        });
    });

  }


}

我的更新按钮得到一个元素的数据将被更新,但是当我点击提交时在我的数据库中创建了其他元素

设备控制员:

namespace TreeApi.Controllers
{
    [ApiController]
    [Route("Api/[Controller]")]
    public class EquipmentController : ControllerBase
    {
        private readonly ContextEquipment _ContextEquipment;

        public EquipmentController (ContextEquipment context)
        {
            _ContextEquipment = context;
        }

        [HttpGet]
        public async Task<ActionResult<IEnumerable<Equipments>>> GetAllAsync()
        {
         return await _ContextEquipment.Equipment.ToListAsync();
        }

        [HttpGet("{EquipmentsID}")]
        public async Task<ActionResult<Equipments>> GetEquipmentAsync(int EquipmentsID)
        {
            Equipments equipment = await _ContextEquipment.Equipment.FindAsync(EquipmentsID);

            if(equipment == null)
            {
                return NotFound();
            }

            return equipment;
        }

        [HttpPost]
        public async Task<ActionResult<Equipments>> PostEquipmentAsync(Equipments equipments)
        {   
            await _ContextEquipment.Equipment.AddAsync(equipments);
            await _ContextEquipment.SaveChangesAsync();

            return Ok();
        }
        [HttpPut]
        public async Task<ActionResult> PutEquipmentAsync(Equipments equipments)
        {
            _ContextEquipment.Equipment.Update(equipments);
            await _ContextEquipment.SaveChangesAsync();

            return Ok();

        }

        [HttpDelete("{EquipmentsID}")]
        public async Task<ActionResult> DeleteEquipmentAsync(int EquipmentsID)
        {
           Equipments equipment = await _ContextEquipment.Equipment.FindAsync(EquipmentsID);
            _ContextEquipment.Remove(equipment);
            await _ContextEquipment.SaveChangesAsync();

            return Ok();
        }
    }
}

启动:

namespace TreeApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
    
        public IConfiguration Configuration { get; }
    
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddDbContext<ContextEquipment>(options => options.UseSqlServer
                (Configuration.GetConnectionString("ConnectionDB")));
            services.AddCors();
        }
    
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
    
            app.UseHttpsRedirection();
    
            app.UseRouting();
            app.UseCors(options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
    
            app.UseAuthorization();
    
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

关注

在您的 SendFormUpdate 方法中,您错过了分配 id 这是 equipment 的主键。

DialogFormUpdateComponent

public SendFormUpdate(): void {

    let newDate: moment.Moment = moment.utc(this.formG.value.date).local();
    this.formG.value.date = newDate.format("YYYY-MM-DD");
    const equipment: Equipments = this.formG.value;

    this.EquipmentService.PutEquipment(equipment).subscribe(result => {

      alert("Equipment was updated with success");
      this.formG.reset();
      this.dialogRef.close();
    })
}

根据DbContext.Update(Object) method

For entity types with generated keys if an entity has its primary key value set then it will be tracked in the Modified state.

If the primary key value is not set then it will be tracked in the Added state. This helps ensure new entities will be inserted, while existing entities will be updated.

An entity is considered to have its primary key value set if the primary key property is set to anything other than the CLR default for the property type.

因此,将创建新的 Equipment 记录,而不是更新现有记录。


解决方案

确保您需要将 id(主键)的值分配给 equipment 以解决上述问题。

DialogFormUpdateComponent

public SendFormUpdate(): void {
    ...
    
    const equipment: Equipments = this.formG.value;
    equipment.id = this.id;

    ...
}