Нарушение структуры объектов с ограничением УНИКАЛЬНОГО КЛЮЧА

#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);
}