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;
...
}
我正在使用 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;
...
}