1

Having trouble with updating my model using @angular/http method http.put().

The issue is that I just can't update Position at all. I can successfully update any other field and can set any Position when creating with POST.

My angular version is "^4.3.3"

In java my model looks like

public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long id;

    String name;

    String email;

    String phone;

    Date birthDay;

    @JsonBackReference
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "position_id")
    Position position;
}

Projection:

public interface EmployeeProjection {

    Long getId();

    String getName();

    String getEmail();

    String getPhone();

    Date getBirthDay();

    @Value("#{target.position.name}")
    String getPosition();
}

And Position class:

public class Position {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long id;

    String name;
}

In angular template Position:

<md-select mdInput placeholder="Position"
           [(ngModel)]="newEmployee.position">
  <md-option *ngFor="let position of positions | async" [value]="position.name">{{ position.name }}
   </md-option>
</md-select>

My update method in component:

update() {
    let positionName = this.employee.position;
    this.positionService.findByName(positionName).subscribe(position => {
      this.employee.position = position._links.self.href;
      this.employeeService.update(this.employee);
      this.employee.position = positionName;
      this.employeeService.localStorageService.set('employee', this.employee);
    });
  }

And in service:

update(employee: Employee) {
    this.http.put(employee._links.self.href, employee)
      .map((resp: Response) => resp.json())
      .subscribe(() => {
        this.getAll();
      });
    return employee;
  }

In chrome Request:

{
  "name": "Nikolai Morgan",
  "id": 1,
  "position": "http://localhost:9080/api/positions/5",
  "birthDay": "1986-07-01",
  "email": "NikolaiMorgan@gmail.com",
  "phone": "+380840713229",
  "_links": {
    "self": {
      "href": "http://localhost:9080/api/employees/1"
    },
    "employee": {
      "href": "http://localhost:9080/api/employees/1{?projection}",
      "templated": true
    },
    "position": {
      "href": "http://localhost:9080/api/employees/1/position"
    }
  }
}

But response and preview not contain field Position:

{
  "id" : 1,
  "name" : "Nikolai Morgan",
  "email" : "NikolaiMorgan@gmail.com",
  "phone" : "+380840713229",
  "birthDay" : "1986-07-01",
  "_links" : {
    "self" : {
      "href" : "http://localhost:9080/api/employees/1"
    },
    "employee" : {
      "href" : "http://localhost:9080/api/employees/1{?projection}",
      "templated" : true
    },
    "position" : {
      "href" : "http://localhost:9080/api/employees/1/position"
    }
  }
}
MolecularMan
  • 227
  • 2
  • 16

1 Answers1

1

To update entity that has reference to another one, in Spring Data REST you have to use a link to this entity. For example:

@Entity
class Employee {
    //...

    String name;

    @ManyToOne
    Position position;   

    //...
}

@Entity
class Position {
    //...

    String name;

    //...
}

interface EmployeeRepo extends JpaRepository<Employee, Long> {}
interface PositionRepo extends JpaRepository<Position, Long> {}

First we add a position:

POST http://localhost:9080/api/positions

{
    "name": "position1"
}

And get a response like this:

{
    "name": "position1",
    "_links" : {
        "self" : {
          "href" : "http://localhost:9080/api/positions/1"
        },
        "position" : {
          "href" : "http://localhost:9080/api/positions/1"
        }
    }
}

Then add an employee:

POST http://localhost:9080/api/employees

{
    "name": "employee1",
    "employee": "http://localhost:9080/api/positions/1"
}

Then get a response:

{
  "name" : "employee1",
  "_links" : {
    "self" : {
      "href" : "http://localhost:9080/api/employees/1"
    },
    "employee" : {
      "href" : "http://localhost:9080/api/employees/1",
    },
    "position" : {
      "href" : "http://localhost:9080/api/employees/1/position"
    }
  }
}

So if we need to update position we create a new one, then PUT the employee:

PUT http://localhost:9080/api/employees/1

{
    "name": "employee1", 
    "position": "http://localhost:9080/api/positions/2"
}

Or even PATCH it:

PATCH http://localhost:9080/api/employees/1

{
    "position": "http://localhost:9080/api/positions/2"
}
Cepr0
  • 28,144
  • 8
  • 75
  • 101
  • Thanks for solution, i picked variant with PATCH. I'd also would be grateful if you clearify how to update with PUT using existing position and employee – MolecularMan Aug 07 '17 at 20:58
  • In my code you can see i setted link for position too, but that didn't fire. I want to understand where is my mistake – MolecularMan Aug 07 '17 at 22:11
  • Что ты имеешь в виду под "didn't fire"? В Response, который ты привел, ссылка на `position` присутствует: `http://localhost:9080/api/employees/1/position`. Или новая позиция в БД не сохраняется? Или что?.. – Cepr0 Aug 08 '17 at 05:34
  • Да, обновляются все поля, кроме позиции, она просто игнорится, хотя в сеттер она приходит, но в репозитории при сохранении уже старое значение – MolecularMan Aug 08 '17 at 08:05
  • Подключи [логировнаие](https://stackoverflow.com/q/45346905) - посмотри, какие реально запросы идут в базу. И еще, не работает только PUT или PATCH тоже?.. – Cepr0 Aug 08 '17 at 09:30
  • не работает только PUT, если изменять только позицию, то в бд сохранение не идет так как в SimpleJpaRepository#save приходит модель со старым значением, тогда как в сеттер приходит новое – MolecularMan Aug 08 '17 at 10:06
  • @MolecularMan Switch to version 1.4.3 of Spring Boot. It seems that there is a [bug](https://jira.spring.io/browse/DATAREST-1100) in version 1.5.x. (( – Cepr0 Aug 08 '17 at 12:09