【问题标题】:@OneToOne from two classes to same class@OneToOne 从两个班级到同一个班级
【发布时间】:2018-01-16 05:47:13
【问题描述】:

为了更好的理解,我想实现这个:

注意:买方可能没有 ExternalAccount,但卖方必须有。我已经/尝试过的:

买家类:

@Entity
public class Buyer extends User {

    @OneToOne(optional=true, cascade= {CascadeType.MERGE})
    @JoinColumn(nullable=true)
    private ExternalAccount externalAccount;
    //getters and setters

}

卖家类别:

@Entity
public class Seller extends User {

    @OneToOne(optional=false, cascade= {CascadeType.MERGE})
    @MapsId
    @JoinColumn(nullable=false)
    private ExternalAccount externalAccount;
    //getters and setters and other properties

} 

ExternalAccount 类:

@Entity
public class ExternalAccount {

    @Id
    @PrimaryKeyJoinColumn
    private Long id;
    //getters and setters

}

我正在将 Spring Data JPA 与 Spring Boot 一起使用,我希望这样做:

  • 如果没有买家相关但 ExternalAccount 存在(与卖家相关联),则关联它。

  • 如果没有卖方相关但 ExternalAccount 存在(与买方关联),则关联它。

  • 如果不存在 ExternalAccount,则在保存买家/卖家时,创建 ExternalAccount。

我可以使用CascadeType.MERGE 实现类似的行为(在阅读了很多 Stackoverflow 帖子之后),但使用它不尊重@OneToOne 映射。它允许创建许多与同一个 ExternalAccount 相关的买家。

  • 我创建了一个带有数据库测试的 github 项目来重现该问题。

https://github.com/ralphavalon/jpa-mapping

在那里,我有我的示例休息控制器(MappingController):

//Creating buyer example
@RequestMapping(value = "/newBuyer", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Object newBuyer() {
    Buyer buyer = new Buyer();
    buyer.setBirthdate(LocalDateTime.now());
    buyer.setEmail("buyer@email.com");
    buyer.setName("Buyer Name");
    ExternalAccount external = new ExternalAccount();
    external.setId(123L);
    buyer.setExternalAccount(external);
    buyerDao.save(buyer);
    return buyer;
}

//Creating seller example
@RequestMapping(value = "/newSeller", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Object newSeller() {
    Seller seller = new Seller();
    seller.setBirthdate(LocalDateTime.now());
    seller.setEmail("seller@email.com");
    seller.setName("Seller Name");
    ExternalAccount external = new ExternalAccount();
    external.setId(123L);
    seller.setExternalAccount(external);
    sellerDao.save(seller);
    return seller;
}

当我第一次调用/newBuyer 时,它会保存。现在,如果我在调用/newBuyer 之后调用/newSeller,它会返回:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["PRIMARY KEY ON PUBLIC.EXTERNAL_ACCOUNT(ID)"; SQL statement:
insert into external_account (id) values (?) [23505-196]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause

org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.EXTERNAL_ACCOUNT(ID)"; SQL statement:
insert into external_account (id) values (?) [23505-196]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) ~[h2-1.4.196.jar:1.4.196]

【问题讨论】:

  • 如果将 externalAccount 关系移动到 User 类会怎样? (它应该可以为空,因为买家可能没有帐户)
  • 那么理论上我可以在没有 ExternalAccount 的情况下拥有卖方......这可能是我的出路,但我想要更接近这种方法的东西。它在语义上是正确的。

标签: java jpa spring-boot spring-data spring-data-jpa


【解决方案1】:

我通过这些更改解决了问题:

  • 更改类的映射:

买家类:

@Entity
public class Buyer extends User {

    @OneToOne(optional=true, cascade= {CascadeType.MERGE})
    @JoinColumn(nullable=true, unique=true)
    private ExternalAccount externalAccount;
    //getters and setters

}

卖家类:

@Entity
public class Seller extends User {

    @OneToOne(optional=false, cascade= {CascadeType.MERGE})
    @JoinColumn(nullable=false, unique=true)
    private ExternalAccount externalAccount;
    //getters and setters

}

ExternalAccount 类:

@Entity
public class ExternalAccount {

    @Id
    private Long id;
    //getters and setters

}

还有最重要的部分:Override Spring Data JPA save method以使用entityManager.merge

@Service
public class BuyerService {

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    public Buyer save(Buyer buyer) {
        return entityManager.merge(buyer);
    }

}

SellerService 也是如此。

【讨论】:

    猜你喜欢
    • 2017-11-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多