Jpa 一对一单向关系

Jpa 一对一单向关系,jpa,repository,spring-data,Jpa,Repository,Spring Data,我有两个实体,AP和APStatus,处于一对一的单向关系中。只有AP需要能够访问APStatus。飞天星只需要知道AP的id,它也是飞天星的主键。本质上,APStatus就像一个嵌入的对象,但我想要一个单独的表。以下是我所拥有的: 我的实体 @Entity public class AP { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="ID", nullable=false)

我有两个实体,AP和APStatus,处于一对一的单向关系中。只有AP需要能够访问APStatus。飞天星只需要知道AP的id,它也是飞天星的主键。本质上,APStatus就像一个嵌入的对象,但我想要一个单独的表。以下是我所拥有的:

我的实体

@Entity
public class AP {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="ID", nullable=false)
    private int id;

    @OneToOne
    private APStatus apStatus;

    //Getters and setters
}

@Entity
public class APStatus {

    @Id
    @Column(name="AP_ID", nullable=false)
    private int apId;

    //Getters and setters
}
我的测试

public class APRepositoryTest {

    @Autowired
    APRepository repository;

    @Autowired
    APStatusRepository statusRepository;

    @Test
    public void test() {
        AP ap = new AP();
        APStatus status = new APStatus();
        statusRepository.save(status);
        ap.setApStatus(status);
        repository.save(ap);
        status.setApId(ap.getId());

        AP dbAp = repository.findOne(ap.getId());
        assertNotNull(dbAp);
        assertNotNull(dbAp.getApStatus());
        assertEquals(dbAp.getId(), dbAp.getApStatus().getApId());
    }

}
assertEquals失败,这是意料之中的:但是失败了。我已经知道为什么,我在保存状态和ap后设置状态的apId字段。但在保存之前设置它的问题是,我会将字段设置为零,因为在执行repository.saveap之后,在本例中,ap的id会自动生成为新值1。我已经尝试过让这种关系具有双向性,并添加层叠效果,但到目前为止,我还没有成功。有人能给我指出正确的方向或告诉我如何解决这个问题吗?提前谢谢

编辑:现在我将使关系双向,并使apId属性的APStatus类中的getter方法如下所示。如果有人有更好的答案,请分享

public int getApId() { 
    return ap.getId(); 
}

首先,您不能更改实体ID。它只设置一次以标识实体。之后,您将强制实例引用完全不同的内容,这在JPA中是不受支持的

这意味着,如果status.setApId调用更改apId字段,则只能使用实际值进行设置

第二,我不太理解美联社对飞天星的引用。您的AP是否有APStatus的外键,或者您是否打算使用AP.ID APStatus.AP_ID关系?我的猜测是,它旨在重用AP.ID APStatus.AP_ID关系,因为这似乎更常见,但只会影响映射它的方式

通过先保存AP,在ApStatus中使用其ID并保存,然后更新关系,您可以在不更改映射的情况下实现此功能:

    AP ap = new AP();
    APStatus status = new APStatus();
    repository.save(ap);
    status.setApId(ap.getId());
    statusRepository.save(status);
    ap.setApStatus(status);
    repository.save(ap);
或者,您可以使用JPA 2.0的驱动标识更改映射,设置级联设置,然后仅保存AP或APStatus:

@Entity
public class AP {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="ID", nullable=false)
    private int id;

    @OneToOne(mappedBy = "ap", cascade=CascadeType.ALL, orphanRemoval = true)
    private APStatus apStatus;

    //Getters and setters
}

@Entity
public class APStatus {

    @Id
    @OneToOne
    @JoinColumn(name="AP_ID")
    private AP ap;

    //Getters and setters
}
然后,您可以简单地使用:

    AP ap = new AP();
    APStatus status = new APStatus();
    status.setAp(ap);
    ap.setApStatus(status);
    repository.save(ap);

令人惊叹的你的第一个建议奏效了。我从来不知道你可以像那样打两次电话给repository.saveap。正如你可能知道的那样,我对这件事很在行。至于你的第二个建议,如果我想让AP成为关系的拥有方,我会将mappedBy、cascade和OrphanerRemoving属性放在APStatus类中,对吗?是的,现在保存两次东西真的可以挽救我的生命。非常感谢您的帮助!Mappedby用于指示另一方在数据库级别控制/拥有关系。级联和孤立删除与此无关,可以在级联JPA操作或删除取消引用的实体有意义的地方使用。