Компонентный первичный ключ, внешний ключ. Ссылка на объект или ключ?

У меня есть два класса Foo и Bar. Таблицы в базе данных выглядят следующим образом:

|Foo|
|id : INT (PK) | bar_id : INT (PK, FK) |

|Bar|
|id : INT (PK) |

Обычно я бы отображал его следующим образом:

@Entity
public class Bar
{
    @Id
    @Column(name = "id")
    private int id;

    @OneToMany
    private Set<Foo> foo;
}

@Entity
public class Foo
{
    @EmbeddedId
    private FooPK key;

    @MapsId("barId")
    @ManyToOne
    @JoinColumn(name = "bar_id", referencedColumnName = "id")
    private Bar bar;
}

@Embeddable
public class FooPK
{
    @Column(name = "id")
    private int id;
    @Column(name = "bar_id")
    private int barId;
}

Однако идентификатор в FooPK слабо сопоставляется и должен быть подключен вручную. Я бы предпочел решение, которое отображает использование объектов вместо свободных идентификаторов. Я пробовал следующее, но (конечно) это не сработало, но я думаю, что это дает представление о том, чего я хотел бы достичь:

@Entity
public class Bar
{
    @Id
    @Column(name = "id")
    private int id;

    @OneToMany
    private Set<Foo> foo;
}

@Entity
public class Foo
{
    @EmbeddedId
    private FooPK key;

    @MapsId("barId")
    @ManyToOne
    @JoinColumn(name = "bar_id", referencedColumnName = "id")
    @Access(AccessType.FIELD)
    private Bar getBar()
    {
        return key.getBar();
    }
}

@Embeddable
public class FooPK
{
    @Column(name = "id")
    private int id;

    @Transient
    private Bar bar;

    //....

    @Column(name = "bar_id")
    @Access(AccessType.PROPERTY)
    private int getBarId
    {
        return bar.getId();
    }
}

Другая проблема с последним решением заключается в том, что метод getBarId() в FooPK должен иметь метод setBarId(Int). Установка объекта с использованием идентификатора может быть выполнена путем доступа к уровню доступа к данным, однако это (на мой взгляд) нарушает разделение слоев бизнес/домен/данные.

Так что делать? Идите с первым решением и держите идентификаторы в синхронизации вручную или есть другая (лучшая) практика?

Ответы

Ответ 1

Ссылаясь на обсуждение JPA 2: составные классы первичных ключей, внесите следующие изменения в классы Foo и FooPK:

@Entity
public class Foo {

    @EmbeddedId
    private FooPK key;

    @MapsId("barId") //references EmbeddedId property
    @JoinColumn(name = "bar_id", referencedColumnName = "id")
    @ManyToOne
    private Bar bar;
}

@Embeddable
public class FooPK {

    @Column(name = "id")
    private int id;
    @Column(name = "bar_id")
    private int barId;
}

Я предлагаю сначала сделать его работу с доступом FIELD, а затем применить доступ к PROPERTY.

Так что делать? Пойдите с первым решением и сохраните идентификаторы в синхронизации вручную или есть другая (лучшая) практика?

Спасите себя от боли - автоматически создавайте идентификаторы.