@PrimaryKeyJoinColumn с двунаправленным отношением @OneToOne - PullRequest
4 голосов
/ 04 января 2010

У меня есть два объекта Mat и MatImage, родительский и дочерний, соответственно. Первичным ключом MatImage является идентификатор Mat, и они соединяются отношениями один-к-одному.

Если я правильно понимаю двунаправленное отношение, дочерний объект будет знать о родителе, если я сделаю что-то вроде matImage.setMat (mat). Я думаю, что первичный ключ будет заполнен в этот момент, но это не так. Я знаю это, потому что sql выдает исключение при попытке вставить MatImage с # 0 в качестве matId.

Другой вопрос связан с проблемой n + 1. Я хотел бы лениво загрузить дочерний объект, потому что не весь мат имеет matimage. Я могу попробовать изменить @OneToOne на @ManyToOne, но не уверен, как это можно сделать в двух направлениях. Любая помощь будет оценена. Спасибо.

Вот сущности:

// Mat

@Entity
@Table(name="mat")
public class Mat implements Serializable {
 @Id
 @GeneratedValue(generator="SeqMat")
 @SequenceGenerator(name="SeqMat", sequenceName="seq_mat_id")
    int id

    @OneToOne(mappedBy="mat", optional=true, fetch=FetchType.LAZY)
 @PrimaryKeyJoinColumn(name="id", referencedColumnName="matId")
 @Cascade([ALL, DELETE_ORPHAN])
 MatImage matImage

    int matTemplateId
    int number
    ... 
}


     // MatImage
    @Entity
    @Table(name="matimage")
    public class MatImage implements Serializable {
        @Id
        int matId

        @OneToOne(optional=true, fetch=FetchType.LAZY)
        @JoinColumn(name="matId", referencedColumnName="id")
        Mat mat

        @Column(name="img_eventid")
        int eventId

        ...
}

Ответы [ 2 ]

4 голосов
/ 11 января 2010

Я не уверен, что вы действительно хотите. Но вы можете использовать что-то вроде следующего, чтобы установить ваши двунаправленные отношения.

@Entity
public class Mat implements Serializable {

    private MutableInt id = new Mutable(-1);

    private MatImage matImage;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO, generator="SeqMat")
    @SequenceGenerator(name="SeqMat", sequenceName="seq_mat_id")
    public Integer getId() {
        return this.id.intValue;
    }

    public void setId(Integer id) {
        this.id.setValue(id)
    }

    public void setIdAsMutableInt(MutableInt id) {
        this.id = id;
    }

    @OneToOne(fetch=FetchType.LAZY)
    @PrimaryKeyJoinColumn
    @Cascade({CascadeType.ALL, CascadeType.DELETE_ORPHAN})
    public MatImage getMatImage() {
        return this.matImage;
    }

    public void setMatImage(MatImage matImage) {
        this.matImage = matImage;

        this.matImage.setIdAsMutableInt(this.id);
    }

}

Теперь наш MatImage

@Entity
public class MatImage implements Serializable {

    private MutableInt id = new MutableInt(-1);

    private Mat mat;

    @Id
    public Integer getId() {
        return this.id.intValue();
    }

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

    public void setIdAsMutableInt(MutableInt id) {
        this.id = id;
    }

    @OneToOne(fetch=FetchType.LAZY)
    @PrimaryKeyJoinColumn
    public Mat getMat() {
        return mat;
    }

    public void setMat(Mat mat) {
        this.mat = mat;

        this.mat.setIdAsMutableInt(this.id);
    }

}

Пара советов

Спецификация JPA не включает стандартизированный метод для решения проблемы генерации общего первичного ключа

Это объясняет, почему я использую org.apache.commons.lang.mutable.MutableInt , поскольку Mat и MatImage совместно используют один и тот же объект (id) в памяти .

Теперь вы можете использовать что-то вроде:

Mat mat = new Mat();
MatImage matImage = new MatImage();

/**
  * Set up both sides
  * 
  * Or use some kind of add convenience method To take car of it
  */
mat.setImage(matImage);
matImage.setMat(mat);

session.saveOrUpdate(mat);

Оба будут использовать один и тот же сгенерированный идентификатор.

Совет: поместите конфигурацию аннотации в метод getter вместо поля member. Hibernate использует прокси-объекты. Но прокси работает нормально при использовании аннотации в методе получения, а не при использовании в поле члена.

С уважением,

3 голосов
/ 06 мая 2011

Проблема в том, что JPA по умолчанию не разрешает правильные аннотации для двунаправленных, общих ключей, отношений один-к-одному. Hibernate имеет идеальную конструкцию как раз для этого, но, пожалуйста, обратите внимание на порядок, а также на конкретные параметры аннотаций (вы также можете прочитать ссылку на hibernate, но их пример не будет работать, если вы предварительно не установите предварительно зависимый объект, Избегайте использования метода ниже - который в основном сохраняет оба объекта за один раз). В этом примере каждое задание обрабатывает сообщение. Job - это «родитель», а message - это зависимый объект. Первичным ключом сообщения будет идентификатор задания (для исключения одного дополнительного столбца в таблице сообщений. Вы также можете создать идентификатор в таблице сообщений, если вам нужно использовать сообщение вне области задания, используя ту же настройку, что и ниже) , Когда задание создано и сообщение прикреплено, hibernate автоматически сохранит оба объекта при вызове jobDao.save.

@Entity
@Table
public class Job implements Serializable{
private Long id;
@Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

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

 @OneToOne(cascade = CascadeType.ALL, mappedBy = "job")
    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
        message.setJob(this);
    }
}

А теперь зависимое сообщение:

@Entity
@Table
public abstract class Message implements Serializable {

private Job job;

    @Id
    @GeneratedValue(generator = "foreign")
    @GenericGenerator(
            name = "foreign",
            strategy = "foreign",
            parameters = {@org.hibernate.annotations.Parameter(name = "property", value = "job")})
    @OneToOne(optional = false, cascade = CascadeType.ALL)
    public Job getJob() {
        return job;
    }

    public void setJob(Job job) {
        this.job = job;
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...