Неверное управление ассоциацией Hibernate от новых / новых к загруженным объектам - почему? - PullRequest
0 голосов
/ 08 мая 2019

Мы хотели бы использовать функциональность управления связями Hibernate (5.4.2.Final) вместе с улучшением байт-кода и полевым доступом. Это работает для некоторых случаев, а не для других за пределами нашего понимания - будем признательны за помощь / руководство.

Мы разобрали случай, как показано ниже, но (старые, возможно, ненужные) аннотации сохранены.

В простейшем случае есть два типа сущностей: «Foo» и «Link». «Ссылка» - это простая направленная связь между двумя сущностями Foo. У Foo есть два свойства коллекции, которые отражают это отношение - входящее и исходящее. Мы начинаем с базы данных, имеющей только один экземпляр Foo с идентификатором 1. Затем мы пытаемся в одной транзакции создать еще один (свежий) Foo (id = 2) и ссылку из Foo # 1 (загружен) на Foo # 2 (свежий). Мы устанавливаем свойства ссылки «от» и «до» и желаем / ожидаем, что управление расширением / связыванием байт-кода обновит «другие стороны» этих отношений. Что происходит, так это то, что freshLink.setTo () отражается в свойстве freshFoo.incoming, а freshLink.setFrom () НЕ отражается в свойствеloadedFoo.outgoing.

Может кто-нибудь помочь нам понять, почему? Что мы делаем неправильно или ожидаем того, чего не должны?

Основной код:

        final Foo loadedFoo = session.get(Foo.class, 1L);
        final Foo freshFoo = new Foo();
        freshFoo.setId(2L);

        final Link freshLink = new Link();
        freshLink.setId(1L);

        freshLink.setTo(freshFoo);
        System.out.println("Other side of 'to' (in freshFoo) updated: " + freshFoo.getIncoming().contains(freshLink));

        freshLink.setFrom(loadedFoo);
        System.out.println("Other side of 'from' (in loadedFoo) updated: " + loadedFoo.getOutgoing().contains(freshLink) );

        session.save(freshFoo);
        session.save(freshLink);
        session.saveOrUpdate(loadedFoo);

Код Foo:

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@javax.persistence.Entity
@Table(name = "foo")
@org.hibernate.annotations.BatchSize(size = 10)
@org.hibernate.annotations.DynamicInsert(false)
@org.hibernate.annotations.DynamicUpdate(false)
@org.hibernate.annotations.SelectBeforeUpdate(false)
@org.hibernate.annotations.Proxy(lazy = false)
@org.hibernate.annotations.Polymorphism(type = org.hibernate.annotations.PolymorphismType.IMPLICIT)
@org.hibernate.annotations.Cache(include = "all", usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE)
@javax.persistence.Access(javax.persistence.AccessType.FIELD)
public class Foo {

    @Id
    @Column(name = "id", nullable = false, updatable = false)
    @org.hibernate.annotations.Type(type = "long")
    private Long id = null;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "to")
    @org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.EXTRA)
    @org.hibernate.annotations.OptimisticLock(excluded = false)
    @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
    @org.hibernate.annotations.NotFound(action = org.hibernate.annotations.NotFoundAction.EXCEPTION)
    private Set<Link> incoming = new HashSet<>();

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "from")
    @org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.EXTRA)
    @org.hibernate.annotations.OptimisticLock(excluded = false)
    @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
    @org.hibernate.annotations.NotFound(action = org.hibernate.annotations.NotFoundAction.EXCEPTION)
    private Set<Link> outgoing = new HashSet<>();

    public Long getId() {
        return id;
    }

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

    public Set<Link> getIncoming() {
        return incoming;
    }

    public Set<Link> getOutgoing() {
        return outgoing;
    }

    public void addIncoming(Link link) {
        this.incoming.add(link);
    }

    public void addOutgoing(Link link) {
        this.outgoing.add(link);
    }
}

Код ссылки:

import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@javax.persistence.Entity
@Table(name = "link")
@org.hibernate.annotations.BatchSize(size = 100)
@org.hibernate.annotations.DynamicInsert(false)
@org.hibernate.annotations.DynamicUpdate(false)
@org.hibernate.annotations.SelectBeforeUpdate(false)
@org.hibernate.annotations.Proxy(lazy = false)
@org.hibernate.annotations.Polymorphism(type = org.hibernate.annotations.PolymorphismType.IMPLICIT)
@org.hibernate.annotations.Cache(include = "all", usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE)
@javax.persistence.Access(javax.persistence.AccessType.FIELD)
public class Link {
    @Id
    @Column(name = "id", nullable = false, updatable = false)
    @org.hibernate.annotations.Type(type = "long")
    private Long id = null;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "from_id", nullable = false)
    @org.hibernate.annotations.LazyToOne(org.hibernate.annotations.LazyToOneOption.NO_PROXY)
    @org.hibernate.annotations.OptimisticLock(excluded = false)
    @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SELECT)
    @org.hibernate.annotations.NotFound(action = org.hibernate.annotations.NotFoundAction.EXCEPTION)
    private Foo from;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "to_id", nullable = false)
    @org.hibernate.annotations.LazyToOne(org.hibernate.annotations.LazyToOneOption.NO_PROXY)
    @org.hibernate.annotations.OptimisticLock(excluded = false)
    @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SELECT)
    @org.hibernate.annotations.NotFound(action = org.hibernate.annotations.NotFoundAction.EXCEPTION)
    private Foo to;

    public Long getId() {
        return id;
    }

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

    public Foo getFrom() {
        return from;
    }

    public void setFrom(Foo from) {
        this.from = from;
    }

    public Foo getTo() {
        return to;
    }

    public void setTo(Foo to) {
        this.to = to;
    }
}

1 Ответ

0 голосов
/ 08 мая 2019

В вышеприведенном случае управление связыванием Hibernate (улучшение байт-кода) не загружает автоматически обратное сопоставление (если оно еще не загружено), а когда оно не загружено, оно не управляет им.

Обходные пути:

  1. Обеспечение загрузки другой стороны ассоциации (либо с нетерпением, либо путем доступа к ней) ДО необходимо управление ассоциацией.

  2. Сброс сеанса / изменений либо явно (метод Session.flush ()), либо с использованием FlushMode.AUTO или FlushMode.ALWAYS.

...