首页 > 解决方案 > 如何映射 3 个实体之间的 oneToone 和 OneToMany 关系?

问题描述

我正在尝试在 JPA 中编程这种关系,但似乎在这里迷失了。这是我的 ER 模型描述。我有一个Customer,其中一个有一个,其中Depot包含Depot股票(股票)。所以这就是我的想法。每个Customer人都有一个Depot(有关系)1:1,一个仓库可以包含更多的股份(股票)。仓库 --> 共享 (1:m)

我有以下代码。

客户.java

@Entity
@NamedQuery(name = "Customer.getAll", query = "SELECT c FROM Customer c") 
public class Customer implements Serializable {
    private static final long serialVersionUID = 101L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id; //todo: for standard way of defining primary key

    @NotNull
    private String username;

    @NotNull
    private String firstName;

    @NotNull
    private String lastName;


    @OneToOne
    @JoinColumn(name="depot_id", nullable=false, updatable=false)
    private Depot depot;


    public Customer() {
        super();
    }

}

仓库.java

@Entity
public class Depot  implements Serializable{
    private static final long serialVersionUID = 102L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    /*@Column(name = "id", updatable = false, nullable = false)*/
    @JoinColumn(name = "customer_id")
    private Long id;


    @OneToMany(mappedBy = "tdepot")
    private List<Share> lshares;

    //todo: Total estimated value in USD
    @Transient
    private BigDecimal totalValue = new BigDecimal(0.0);


    public Depot(){
        super();
    }

    @PostConstruct
    public void init(){
        if(lshares == null){
            lshares = new ArrayList<>();
        }

    }
}

分享.java

@Entity
public class Share implements Serializable{

    private static final long serialVersionUID = 103L;


    @Id
    protected String symbol;


    @NotNull
    protected String companyName;

    @NotNull
    protected Long floatShares;
    protected BigDecimal lastTradePrice;

    @NotNull
    @Temporal(TemporalType.TIMESTAMP)
    private java.util.Date lastTradeTime;

    @NotNull
    protected String stockExchange;


    @ManyToOne(optional=false)
    @JoinColumn(name="depot_id", nullable=false, updatable=false)
    private Depot tdepot;

    public Share(){
        super();
        lastTradeTime = new Date();
    }
}

使用上面的代码,我什至可以创建并保留一个客户。我做错了映射吗?

如果我尝试将数据持久保存到上述数据库中,则会收到以下错误消息。[缩短可读性]

引起:javax.persistence.PersistenceException:org.hibernate.PersistentObjectException:分离的实体传递给坚持:net.dsfinance.bank.ejb.entity.Customer

With .merge instead of persist

12:48:48,875 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper](默认任务 46)SQL 错误:23502,SQLState:23502 12:48:48,876 错误 [org.hibernate.engine.jdbc.spi. SqlExceptionHelper](默认任务 46)列“DEPOT_ID”不允许为 NULL;SQL 语句:插入客户(地址、depot_id、名字、姓氏、密码、角色、用户名、id)值(?,?,?,?,?,?,?,?) [23502-173] 12:48: 48,883 INFO [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl](默认任务 46)HHH000010:在批处理发布时,它仍然包含 JDBC 语句 12:48:48,888 WARN [com.arjuna.ats.arjuna](默认任务 46) ARJUNA012125: TwoPhaseCoordinator.beforeCompletion - SynchronizationImple< 0:ffffc0a80869:-53b30100:5af571b4:4d, org.jboss.as.txn.service.internal.tsr 失败。

:javax.persistence.PersistenceException:org.hibernate.exception.ConstraintViolationException:无法在org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert的org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692)执行语句(AbstractEntityManagerImpl.java:1602) 在 org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1608) 在 org.hibernate.jpa.internal.EntityManagerImpl$CallbackExceptionMapperImpl.mapManagedFlushFailure(EntityManagerImpl.java:235) 在 org. hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2967) 在 org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2339) 在 org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl。beforeTransactionCompletion(JdbcCoordinatorImpl.java:485) 在 org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl.beforeCompletion(JtaTransactionCoordinatorImpl.java:316) 在 org.hibernate.resource.transaction.backend.jta.internal.synchronization。 SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:47) 在 org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:37)internal.synchronization.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:47) 在 org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:37)internal.synchronization.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:47) 在 org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:37)

h2.jdbc.JdbcSQLException:列“DEPOT_ID”不允许为 NULL;SQL 语句:

这是我使用的时候entitymanger.persist(),谷歌搜索后,有人建议我应该使用merge但仍然不允许我将客户添加到数据库中。

我想实现什么:我想为一个简单的交易服务 java EE 应用程序创建一个数据库,客户有一个仓库。包含购买特定客户的所有股票的仓库。我如何实现这一目标?谢谢

标签: javajpaentity

解决方案


由于您没有提供用于持久化实体的代码,因此我不会详细说明这一点(除非您编辑您的帖子),我将重点介绍解决此类问题的步骤。

首先,尝试简单,然后详细说明:depot从类中删除您的对象,Customer以确保您的 Id 生成策略正常工作。如果没有,您需要先修复它,具体取决于您的数据库。你需要能够坚持一个简单的Customer.

一旦你可以保留一个客户,depot就添加一个(就像现在一样),而不是它的shares集合。与以前相同的步骤,直到您可以保留客户及其仓库。

最后,添加shares集合,就像现在一样。IMO,因为我不熟悉 @PostConstruct 注释,所以我将其删除并替换为普通的旧集合初始化:

private List<Share> lshares = new ArrayList<>();

如果以上都不起作用,那显然不再是映射问题了!


推荐阅读