0

I am trying to program this relationship in JPA but seems to be lost in here. This is my ER-model decription. I have a Customer, which one have one Depot and this Depot contains shares(stocks). So this is what I think. Every Customer has a Depot that is (has relationship) 1:1 and a Depot can contain more Shares(stocks). Depot --> Shares (1:m)

I have the following code.

Customer.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();
    }

}

Depot.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<>();
        }

    }
}

Shares.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();
    }
}

With the above code I can even create and persist a Customer. Am I doing the mapping wrongly?

I am getting the following error message if I try to persist data into the above Database. [shorten for readibility]

Caused by: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: net.dsfinance.bank.ejb.entity.Customer

With .merge instead of persist

12:48:48,875 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-46) SQL Error: 23502, SQLState: 23502 12:48:48,876 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (default task-46) NULL not allowed for column "DEPOT_ID"; SQL statement: insert into Customer (address, depot_id, firstName, lastName, password, role, username, id) values (?, ?, ?, ?, ?, ?, ?, ?) [23502-173] 12:48:48,883 INFO [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl] (default task-46) HHH000010: On release of batch it still contained JDBC statements 12:48:48,888 WARN [com.arjuna.ats.arjuna] (default task-46) ARJUNA012125: TwoPhaseCoordinator.beforeCompletion - failed for SynchronizationImple< 0:ffffc0a80869:-53b30100:5af571b4:4d, org.jboss.as.txn.service.internal.tsr.JCAOrderedLastSynchronizationList@6806a37a

: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1608) at org.hibernate.jpa.internal.EntityManagerImpl$CallbackExceptionMapperImpl.mapManagedFlushFailure(EntityManagerImpl.java:235) at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2967) at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2339) at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485) at org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl.beforeCompletion(JtaTransactionCoordinatorImpl.java:316) at org.hibernate.resource.transaction.backend.jta.internal.synchronization.SynchronizationCallbackCoordinatorNonTrackingImpl.beforeCompletion(SynchronizationCallbackCoordinatorNonTrackingImpl.java:47) at org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:37)

Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:112) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:207) at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2897) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3397) at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:89) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:582) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456) at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337) at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282) at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:465) at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2963) ... 129 more Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "DEPOT_ID"; SQL statement:

This was when i was using entitymanger.persist(), after googling, some people suggested that I should use merge but still didn't allow me to add customer into the database.

What do I want to achieve: I want to create a database for a simple tradingservice java EE application with, Customer having a Depot. Depot containing all the shares bought buy a specific Customer. How do I achieve this? Thanks

Seek Addo
  • 1,871
  • 2
  • 18
  • 30
  • 1
    depends on what you need; what's your problem anyway? – HBo May 11 '18 at 10:10
  • @HBo my problem is how to link the relationship between the entities correctly. so that i can persist data into the database. as of now I can't. running this on Jboss wildfly server. – Seek Addo May 11 '18 at 10:13
  • I was thinking the relationship between Depot und Customer is wrong, 1:m instead of the 1:1. Because the Depot table should contain a lot of Depot shares information for different customers. – Seek Addo May 11 '18 at 10:14
  • 1
    that's where the background is important (=your needs). For instance, if `depot` is not very important, you could map a collection of `shares` using and `@ElementCollection` annotation (just to avoid having to do customer.getDepot().getShares(). Why can't you run this? What exception, ...? – HBo May 11 '18 at 10:17
  • @HBo the ElementCollection sounds good. just to cut off the long way. But I don't know how to do that. Can you please provide a solution to make this simple. Customer and shares. Thanks. – Seek Addo May 11 '18 at 10:20
  • ElementCollection is supposed to be only for 'simple' types (see this https://stackoverflow.com/questions/8969059/difference-between-onetomany-and-elementcollection), not sure it would fit your needs because you'd have to 'choose' a column to collect inside `Shares` (lastTradePrice for example) – HBo May 11 '18 at 10:24
  • @HBo DN1, I updated my question now to be more specific. Thanks for your contribution. Please I am new to JPA and the whole Java EE thing. we patient with me. – Seek Addo May 11 '18 at 10:41
  • @HBo I restarted the Server and posted the full error message in my question? Is there any work around this problem. I think is because of my wrong mapping. – Seek Addo May 11 '18 at 10:52
  • in real world/normal bank a customer can have multiple depots ... and the relationship between share and depot should be a **many-to-many**! – xerx593 May 11 '18 at 11:00
  • ..(but with the current setup) in case of `persist`: you must persist the depot (id must be generated), before you persist the customer. in case of `merge` ... (`updatebale= false` can be to blame) ...depot_id is null! (??) – xerx593 May 11 '18 at 11:09

1 Answers1

0

Since you didn't provide the code you use to persist your entities, I won't elaborate on this (unless you edit your post) and I'm gonna focus on the steps to take care of such a problem.

First of all, try simple, then elaborate: remove your depot object from the Customer class to make sure that your Id generation strategy works properly. If not, you need to fix it first, depending on your database. You need to be able to persist a simple Customer.

Once you can persist a customer, add a depot to it (just like it is right now), without its shares collection. Same steps than before, until you can persist an Customer and its Depot.

Finally, add the shares collection, like it is right now. IMO, because I'm not familiar with the @PostConstruct annotation, I'd remove it and replace by a plain old collection initialization:

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

If none of the above works, it's clearly not a mapping problem anymore!

HBo
  • 635
  • 6
  • 16