#angular #asp.net-core #angular-material
#angular #asp.net-ядро #angular-материал
Вопрос:
Итак, у меня есть выбор в моей форме, который правильно получает «категории» из моих «записей» из базы данных. Проблема в том, что когда я пытаюсь вставить новые данные, я получаю сообщение об ошибке, потому что EF пытается создать новую категорию с тем же именем вместо использования существующей, а имя имеет уникальное ограничение. Есть идеи о том, как это обойти?
Это моя форма:
<mat-form-field appearance="fill">
<mat-label>Category</mat-label>
<mat-select name="category" #category="ngModel" [(ngModel)]="service.formData.category.name" >
<mat-option *ngFor="let category of categories | async " [value]="category.name">
{{category.name}}
</mat-option>
</mat-select>
</mat-form-field>
Это машинописный текст:
export class BudgetFormComponent implements OnInit {
categories : Observable<any>;
constructor(public service: BudgetService) { }
ngOnInit(): void {
this.resetForm();
this.categories = this.service.getCategories();
}
resetForm(form?: NgForm) {
if (form != null)
form.resetForm();
this.service.formData = {
id: 0,
date: new Date,
name: "",
value: 0,
categoryId: 0,
category: new Category(),
type: ""
}
}
onSubmit(form: NgForm) {
console.log(form.value);
if (this.service.formData.id == 0)
this.insertRecord(form)
else
this.updateRecord(form)
}
insertRecord(form: NgForm) {
this.service.postRecordDetail().subscribe(
res => {
console.log("Insert ok")
this.resetForm(form);
this.service.getRecords();
},
err => {
console.log(err);
}
);
}
это метод post в службе
export class BudgetService {
formData: Record;
ELEMENT_DATA: Record[] = []
dataSource = new MatTableDataSource<Record>(this.ELEMENT_DATA);
// readonly rootURL = 'https://boxestest.azurewebsites.net/api';
readonly rootURL = 'https://localhost:5001/api';
private fbSubs: Subscription[] = [];
constructor(private http: HttpClient) { }
postRecordDetail() {
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
}
return this.http.post(this.rootURL '/records', this.formData, httpOptions)
}
Это контроллер (Asp.net Webapi)
[HttpPost]
public ActionResult<Record> AddRecord(Record record)
{
_context.Records.Add(record);
_context.SaveChanges();
return CreatedAtAction("GetRecordById", new { id = record.Id }, record);
}
Комментарии:
1. Нам нужно увидеть больше кода; начните с метода POST и метода, который создает данные в базе данных.
2. Внешний интерфейс, скорее всего, не будет проблемой здесь. Внутренний код, который включает в себя модели EF и службы, которые вы используете для добавления данных в серверную часть, был бы полезен
Ответ №1:
Изначально Record record
объект не отслеживается EF Core, как Category record.category
и объект. После вызова _context.Records.Add(record)
ядро EF начинает отслеживать их и устанавливает для обоих объектов значение Added
. Затем после вызова SaveChanges
обе сущности добавляются в качестве новых строк в базе данных.
[HttpPost]
public ActionResult<Record> AddRecord(Record record)
{
_context.Records.Add(record);
// Category was not tracked initially. EF core starts to track it and SaveChanges will add a new row to the db
_context.SaveChanges();
return CreatedAtAction("GetRecordById", new { id = record.Id }, record);
}
Есть несколько способов, которыми мы могли бы решить эту проблему.
1)
Добавить _context.Entry(record.Category).State = EntityState.Unchanged;
. Это сообщает EF core, что Category
существует в базе данных и не было изменено.
[HttpPost]
public ActionResult<Record> AddRecord(Record record)
{
_context.Records.Add(record);
_context.Entry(record.Category).State = EntityState.Unchanged;
_context.SaveChanges();
return CreatedAtAction("GetRecordById", new { id = record.Id }, record);
}
Наши данные JSON будут выглядеть примерно так (некоторые свойства опущены):
var raw = JSON.stringify({"id":0,"name":"R2","categoryId":1,"category":{"id":1,"name":"C1"}});
2)
Мы отправляем только те данные, которые нам нужны для создания нашего нового Record
.
Удалите category
из наших данных JSON и используйте только те categoryId
, чтобы определить, какие Category
мы хотим на Record
:
var raw = JSON.stringify({"id":0,"name":"R3","categoryId":1});
Метод POST не изменится:
[HttpPost]
public ActionResult<Record> AddRecord(Record record)
{
_context.Records.Add(record);
_context.SaveChanges();
return CreatedAtAction("GetRecordById", new { id = record.Id }, record);
}