Розміщення асоціації субресурсів @OneToMany у Spring Data REST


103

В даний час у мене є програма Spring Boot, яка використовує Spring Data REST. У мене є об'єкт домену , Postякий має @OneToManyвідношення до іншої області особи, Comment. Ці класи структуровані так:

Post.java:

@Entity
public class Post {

    @Id
    @GeneratedValue
    private long id;
    private String author;
    private String content;
    private String title;

    @OneToMany
    private List<Comment> comments;

    // Standard getters and setters...
}

Коментар.java:

@Entity
public class Comment {

    @Id
    @GeneratedValue
    private long id;
    private String author;
    private String content;

    @ManyToOne
    private Post post;

    // Standard getters and setters...
}

Їхні сховища Spring REST JPA є базовими реалізаціями CrudRepository:

PostRepository.java:

public interface PostRepository extends CrudRepository<Post, Long> { }

CommentRepository.java:

public interface CommentRepository extends CrudRepository<Comment, Long> { }

Точка входу до програми - це стандартна, проста програма Spring Boot. Все налаштовано на складі.

Application.java

@Configuration
@EnableJpaRepositories
@Import(RepositoryRestMvcConfiguration.class)
@EnableAutoConfiguration
public class Application {

    public static void main(final String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Здається, все працює правильно. Коли я запускаю програму, все, здається, працює правильно. Я можу розмістити новий об'єкт "Пост", щоб він http://localhost:8080/postsтак:

Тіло: {"author":"testAuthor", "title":"test", "content":"hello world"}

Результат за адресою http://localhost:8080/posts/1:

{
    "author": "testAuthor",
    "content": "hello world",
    "title": "test",
    "_links": {
        "self": {
            "href": "http://localhost:8080/posts/1"
        },
        "comments": {
            "href": "http://localhost:8080/posts/1/comments"
        }
    }
}

Однак, коли я виконую GET у http://localhost:8080/posts/1/commentsмене, {}повертається порожній об’єкт , і якщо я намагаюся розмістити коментар до того ж URI, я отримую метод HTTP 405 не дозволений.

Який правильний спосіб створити Commentресурс і пов’язати його з цим Post? Я хотів би уникати публікації, http://localhost:8080/commentsякщо можливо, безпосередньо .


9
Через 7 днів і досі не пощастило. Якщо хтось знає спосіб змусити цю поведінку працювати, будь ласка, повідомте мене. Дякую!
ccampo

ви використовуєте @RepositoryRestResource або контролер? Було б корисно побачити і цей код.
Магнус Лассі

Я використовую дані для завантаження даних Spring, це працювало для мене http://stackoverflow.com/questions/37902946/add-item-to-the-collection-with-foreign-key-via-rest-call
Таймур

Відповіді:


47

Спершу слід опублікувати коментар, а під час публікації коментаря ви можете створити організацію повідомлень про асоціацію.

Це має виглядати приблизно так:

http://{server:port}/comment METHOD:POST

{"author":"abc","content":"PQROHSFHFSHOFSHOSF", "post":"http://{server:port}/post/1"}

і це буде прекрасно працювати.


2
Це працювало для мене. Просто переконайтеся, що author.postце записується (наприклад, за допомогою сетера чи @JsonValueанотації)
scheffield

1
Чи має це працювати також із запитом виправлення, як при переміщенні коментаря з однієї публікації до іншої?
айканадал

2
Це був би мій (переважно) переважний підхід, але, здається, це не працює для мене. :( Він створює коментар, але не створює рядок у таблиці роздільної здатності (POST_COMMENTS). Будь-які пропозиції щодо вирішення проблеми?
banncee

3
Яким би був підхід для сценарію, наприклад, з об'єктами місця розташування та адреси, де місце проведення повинно бути адресою та адресою ОБОВ'ЯЗКОВО бути пов’язане з місцем розташування? Я маю на увазі ... щоб уникнути створення осиротілої адреси, яка ніколи не може бути призначена ні до чого? Можливо, я помиляюся, але клієнтська програма НІКОЛИ не несе відповідальності за збереження послідовності в базі даних. Я не можу розраховувати на те, що клієнтське додаток створить адресу, а потім обов'язково призначить місце проведення місця. Чи є спосіб POST субресурсу (в даному випадку сутності адреси) зі створенням власне ресурсу, щоб я міг уникнути невідповідності ??
апострофедоттільде

2
Я намагаюся це зробити ( див. Тут ), але чомусь створюється лише ресурс, а не асоціація.
ім'я користувача

55

Якщо припустити, що ви вже виявили URI після URI і, таким чином, URI ресурсу асоціації (вважається $association_uriнаступним), він, як правило, виконує такі кроки:

  1. Дізнайтесь про коментарі щодо управління ресурсами колекції

    curl -X GET http://localhost:8080
    
    200 OK
    { _links : {
        comments : { href : "…" },
        posts :  { href : "…" }
      }
    }
  2. Перейдіть за commentsпосиланням та POSTвашими даними на ресурс:

    curl -X POST -H "Content-Type: application/json" $url 
    {  // your payload // … }
    
    201 Created
    Location: $comment_url
  3. Призначте коментар до публікації, видавши PUTURI асоціації.

    curl -X PUT -H "Content-Type: text/uri-list" $association_url
    $comment_url
    
    204 No Content

Зауважте, що на останньому кроці, згідно специфікації text/uri-list, ви можете надіслати кілька URI, що ідентифікують коментарі, розділені переривом рядка, щоб призначити кілька коментарів одночасно.

Ще кілька приміток до загальних дизайнерських рішень. Приклад публікації / коментарів, як правило, є чудовим прикладом для сукупності, що означає, що я уникаю зворотних посилань з " Commentна", Postа також уникаю CommentRepositoryповністю. Якщо коментарі не мають власного життєвого циклу (якого вони зазвичай не стосуються композиційного стилю), ви, скоріше, отримуєте коментарі, викладені вбудовано безпосередньо, і весь процес додавання та видалення коментарів може бути вирішений шляхом використання JSON Patch . Spring Data REST додав підтримку до цього кандидата в останню версію для майбутньої версії 2.2.


4
Цікаво тут від виборців, що перемоглися, в чому причина голосів;).
Олівер Дротбом

3
Я не впевнений у тих, хто знищив виборців ... Я навіть не маю репутації це робити! Причиною я не обов'язково люблю розміщувати коментарі в рядках з повідомленнями, тому що врахуйте (малоймовірний) сценарій, коли у мене є тисячі коментарів до однієї публікації. Мені хотілося б мати можливість запам’ятати колекцію коментарів, а не отримувати цілу купу їх кожного разу, коли я хочу отримати доступ до вмісту публікації.
ccampo

25
Найінтуїтивніший спосіб для мене написати коментар - це зробити POST для localhost: 8080 / posts / 1 / comments . Хіба це не найпростіший і змістовніший спосіб зробити це? І в той же час ви все одно можете мати спеціальний сховище коментарів. Це не дозволяє весна чи стандарт HAL?
айкаканал

4
@OliverGierke Це все-таки рекомендований / єдиний спосіб зробити це? Що робити, якщо дитина не є нульовою ( @JoinColumn(nullable=false))? Спочатку неможливо надсилати дитину, а потім ПІДКЛЮЧАТИ / ПІДГОТОВИТЬ батьківську асоціацію.
JW Лім

2
Чи є посібник по використанню api, створеного за допомогою весняного відпочинку даних? Я гуглив його протягом 2 годин і нічого не знайшов. Дякую!
Skeeve

2

Існує 2 типи асоціації та складу відображення. У разі асоціації ми використовували концепцію приєднання таблиці, як

Співробітник - 1 до n-> відділ

Таким чином, 3 таблиці будуть створені у випадку працівника асоціації, відділу, службовця_відділу

Потрібно лише створити у вашому коді EmployeeRepository. Крім цього картографування має бути таким:

class EmployeeEntity{

@OnetoMany(CascadeType.ALL)
   private List<Department> depts {

   }

}

Entity Entity не буде містити жодного відображення для ключа forign ... тому тепер, коли ви спробуєте POST-запит на додавання Співробітника з Департаментом в єдиний запит json, він буде доданий ....


1

Я зіткнувся з тим же самим сценарієм, і мені довелося видалити клас сховища для підменю, оскільки я використовував одне до багатьох відображень і витягування даних через основну сутність. Зараз я отримую всю відповідь з даними.


1
Ця річ, про яку ви говорите, може бути легко виконана за допомогою прогнозів
kboom

0

Для відображення oneToMany просто зробіть POJO для того класу, який ви хочете зробити на карті, та @OneToMany анотацію до нього, і внутрішньо він буде відображати його до цього ідентифікатора таблиці.

Також вам потрібно реалізувати інтерфейс Serializable до класу, який ви отримуєте Дані.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.