Сохранение Java JPA Hibernate без вставки ссылочных сущностей

У меня 2 класса:

@Entity
@Table(name = "TableA")
public class EntityA
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id")
    private final Integer id = null;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "BId")
    private EntityB b;

    public EntityA(EntityB b)
    {
        this.b = b;
    }
}

@Entity
@Table(name = "TableB")
public class EntityB
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id")
    private final Integer id = null;

    @OneToOne(mappedBy = "b")
    private final EntityA a = null;
}

Когда я делаю

session.save(new EntityA(new EntityB());

база данных только вставляет запись в TableA и оставляет столбец, который ссылается на TableB как NULL

Если я сначала вставлю b, затем a, он будет работать, но он должен работать и с одним вызовом.

В других вопросах / ответах упоминается, что аннотации неверны, но я не вижу разницы между моим и предоставленными решениями.

Я также попытался добавить CascadeType.PERSIST в обе аннотации @OneToOne, но это тоже не сработало.

Какие ошибки возникают с аннотациями CascadeType и без них?

Klaimmore 17.03.2018 15:35

при текущей настройке ошибок нет, просто нет записей для TableB, раньше у меня для столбца в SQLServer было установлено значение NOT NULL, а затем я получил ошибки вставки, говоря, что я не могу вставить значения NULL для BId

Wietlol 17.03.2018 15:37

Ах, я вижу, мне пришлось использовать CascadeType.ALL вместо ... на самом деле любую комбинацию других, со ВСЕМ на @OneToOne, это сработало

Wietlol 17.03.2018 15:50

@Wietlol это потому, что вы не используете entityManager JPA для сохранения, а вместо этого используете сеанс Hibernate, поэтому вам нужно либо использовать Hibernate org.hibernate.annotations.CascadeType.SAVE_UPDATE, либо, если вы используете JPA @CascadeType, если вы используете ВСЕ, он также будет охватывать каскады Hibernate. Посмотрите здесь и здесь для получения дополнительной информации.

Ranjeet 17.03.2018 20:56

Кажется, это ответ, не могли бы вы дать его в качестве ответа, чтобы я мог отметить его как решение? Кроме того, было бы лучше использовать диспетчер сущностей вместо сеанса гибернации? Я как бы пошел в это с помощью «Это просто должно работать», поэтому я могу выбрать использование чего-то другого, кроме спящего режима, если это уменьшит сложность или ошибки в настройке.

Wietlol 17.03.2018 23:10

@Wietlol Да, лучше придерживаться одного: JPA или Hibernate. Если что-то невозможно с JPA, я не вижу причин использовать сеанс Hibernate. Мой совет: попробуйте использовать JPA для всех ваших нужд. Если что-то невозможно через JPA, вы всегда можете получить сеанс через Session session = em.unwrap(Session.class);.

Ranjeet 22.03.2018 09:17

Просто убедитесь, что вы используете полностью определенные имена для Hibernate в своем коде для аннотаций и классов Hibernate, чтобы, взглянув на код, вы знали, что отклоняется от JPA (поскольку существует много классов с одинаковыми именами в JPA и пространстве имен Hibernate) . Пример: org.hibernate.Query query = session.createQuery(queryString)

Ranjeet 22.03.2018 09:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
7
85
2

Ответы 2

В jpa параметр Cascade по умолчанию - NONE ... поэтому объекты в отношениях (B в вашем случае) по умолчанию не вставляются (сохраняются) ... Вам необходимо аннотировать отношения с помощью @OneToOne (fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)

Проблема, с которой я столкнулся, заключалась в том, что даже с PERSIST он все еще не работал. поскольку cascase может принимать список типов, я пробовал добавлять все больше и больше, но ТОЛЬКО с CascaseTyoe.ALL он работал, больше ничего

Wietlol 17.03.2018 19:09

Прежде всего, вы должны удалить последнее ключевое слово из ваших объектов. Попробуй это:

@Entity
@Table(name = "TableA")
class EntityA {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id")
    private Integer id;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name = "BId")
    private EntityB b;


    public Integer getId() {
        return id;
    }


    public void setId(Integer id) {
        this.id = id;
    }


    public EntityB getB() {
        return b;
    }


    public void setB(EntityB b) {
        this.b = b;
    }


    public EntityA(EntityB b) {
        this.b = b;
        b.setA(this);
    }
}

@Entity
@Table(name = "TableB")
class EntityB {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id")
    private Integer id;

    @OneToOne(mappedBy = "b")
    private EntityA a;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public EntityA getA() {
        return a;
    }

    public void setA(EntityA a) {
        this.a = a;
    }
}

Я использую базу данных Spring boot, hibernate и H2

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        ApplicationContext app =  SpringApplication.run(DemoApplication.class, args);
        ServiceCascade bean = app.getBean(ServiceCascade.class);
        bean.save();
    }
}

@Service
class ServiceCascade {
    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public void save() {
        EntityA entityA = new EntityA(new EntityB());
        entityManager.persist(entityA);
    }
}

Следующие журналы показывают, что два объекта вставлены правильно.

org.hibernate.SQL : insert into tableb (id) values (null)
org.hibernate.SQL : insert into tablea (id, bid) values (null, ?)
o.h.type.descriptor.sql.BasicBinder  : binding parameter [1] as [INTEGER] - [1]

Это не сработало, как я уже упоминал, я уже пытался добавить CascadeType.PERSIST к обеим сторонам. CascadeType.ALL, похоже, работает, и @Cascade из org.hibernate.annotation (как упоминал Ранджит) также работает.

Wietlol 17.03.2018 23:12

Я использую Session :: save из спящего режима, у меня работает менеджер сущностей

Wietlol 17.03.2018 23:24

Другие вопросы по теме