angular - HTTP PUT 正在创建而不是在 Angular 应用程序中更新
问题描述
我正在使用 Angular 开发一个简单的 CRUD 应用程序,当我提交更新表格元素的表单时,它会创建另一个元素而不是更新相同的元素。怎么了?
服务等级:
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
.
对话框窗体更新组件
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();
})
}
对于具有生成键的实体类型,如果一个实体设置了它的主键值,那么它将在修改状态下被跟踪。
如果未设置主键值,则将在已添加状态下对其进行跟踪。这有助于确保插入新实体,同时更新现有实体。
如果主键属性设置为属性类型的 CLR 默认值以外的任何值,则认为实体已设置其主键值。
因此,Equipment
将创建新记录而不是更新现有记录。
解决方案
确保您需要为id
(主键)赋值equipment
以解决上述问题。
对话框窗体更新组件
public SendFormUpdate(): void {
...
const equipment: Equipments = this.formG.value;
equipment.id = this.id;
...
}
推荐阅读
- regex - Ruby 正则表达式锚与字符类 && 相结合
- javascript - Webpack 5 如何禁用压缩并只保留缩小
- java - Iterator.iter() 返回相同的值
- json - 使用 Unix 从输入文件中提取 JSON 数据集中的匹配字符串 id
- reactjs - Redux - InitialState - 数组与对象问题
- python - 有没有办法通过比较一个或多个字符串来创建正则表达式
- python - 对于烧瓶,我如何设置自定义输入的值,但不能获取占位符?
- sql - 这个 SQL 语句的意图是什么?
- java - 在不使用 OR 运算符的情况下检查字符串是否在 Java 中包含多个值?
- c# - 使用 C# 聚合管道图集搜索阶段