JustCodingPlease
JustCodingPlease

Reputation: 29

Hibernate - Mapping three tables with a single save

I am trying to create a project that will use Hibernate to store the objects to the database.

If I simply insert (save) an object that does not contain a mapping with another table everything works fine. However, I have a case where there is a connection between three tables. The tables are the Asset, MonetaryValue and CurrencyType (see below).

When an Asset is inserted, the monetaryValueType must be provided (by the user ) along with the currency type. Asset holds a OneToOne relation with the MonetaryValueType and MonetaryValueType holds a OneToOne relation to the CurrencyType Table. More specifically, below you will find the database tables.

Asset(asset_id,ownerIID,valueID,samID), where valueID is the foreign key to the MonetaryValueType Table (OneToOne undirectional mapping)

MonetaryValueType(mvID, mValue,currencyId), where currencyID is the foreign key to the CurrencyType Table (OneToOne undirectional mapping)

CurrencyType(currencyID,currField,currValue,currSymbol).

The problem is that every time I create the asset object and I am calling the asset service to save the element, Hibernate either create a select query that tries to select from a database table I did never define or Inserts in the currency field with wrong column names (i.e. currency_field instead of currField etc.)

I've tried to play with all the Cascade types but nothing seems to work.

Asset.java

@Entity
@Table(name="asset")
public class Asset implements java.io.Serializable{

    @Id
    @Column(name="assetID", unique = true, nullable = false)
    private long assetID;

    @Column(name="ownerID")
    private long ownerID;

    @OneToOne
    @JoinColumn(name="valueID")
    private MonetaryValueType monetaryValueType;

    @Column(name="samID")
    private long samID;
------------Constructor, Getters , Setters-----
MonetaryValueType.java

@Entity
@Table(name="monetaryvaluetype")
public class  MonetaryValueType{

    @Id
    @Column(name="mvID",nullable = false,unique = true)
    private Long id;

    @Column(name="mValue")
    private double mValue;

    @OneToOne
    @JoinColumn(name="currencyId")
    private CurrencyType currency;
------------Constructor, Getters , Setters-----


CurrencyType.java

@Entity
@Table(name="currencytype")
public class CurrencyType implements java.io.Serializable {

    @Id
    @Column(name="currencyID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int currencyID;

    @Column(name="currField")
    private  String currField;

    @Column(name="currValue")
    private String currValue;

    @Column(name="currSymbol")
    private String currSymbol;
------------Constructor, Getters , Setters-----

Every entity holds its own DAO,DAOImpl, Service and ServiceImpl class. For instance, for the asset class the DAOImpl and ServiceImpl can be found below:

AssetDAOImpl.java

@Repository
public class AssetDAOImpl implements AssetDAO{
    private Logger logger   = LoggerFactory.getLogger(this.getClass());
    //entity manager field
    @Autowired
    private EntityManager entityManager;




    @Override
    public List<Asset> findAll() {
        Session currentSession = entityManager.unwrap(Session.class);
        //create a query
        Query theQuery =
                currentSession.createQuery("from asset",Asset.class);
        //execute query and get result list
        List<Asset> aModelElements = theQuery.getResultList();
        //return the results
        return aModelElements;
    }

    @Override
    public Asset findById(int theId) {
        return null;
    }

    @Override
    public Asset insert(Asset assetElement) {

        //Session currentSession = entityManager.unwrap(Session.class);
        boolean success = false;
        try {

            entityManager.persist(assetElement);
            logger.info("Asset -> {}", assetElement);
            return assetElement;
        }
        catch(Exception e){
            e.printStackTrace();
        }
        return null;
    }

AssetServiceImpl.java

@Service
public class AssetServiceImpl implements AssetService {

    private Logger logger   = LoggerFactory.getLogger(this.getClass());
    private AssetDAO assetDAO;

    @Autowired
    public AssetServiceImpl(AssetDAO theAssetDAO){
        assetDAO=theAssetDAO;
    }

    @Override
    @Transactional
    public List<Asset> findAll() {

        return assetDAO.findAll();
    }

    @Override
    @Transactional
    public Asset findById(int theId) {
        return assetDAO.findById(theId);
    }

    @Override
    @Transactional
    public Asset insert(Asset theAsset) {
        assetDAO.insert(theAsset);
        return theAsset;

    }
...

The class that I use to fill the asset class (and all its children) is:

 UniqueIDGenerator uniqueIDGenerator = new UniqueIDGenerator();
            CurrencyType currencyType = new CurrencyType();
            Asset asset = new Asset();
            MonetaryValueType monetaryValueType = new MonetaryValueType();

            currencyType.setCurrValue(ctx.value().monetaryValueType().currency().CurrencyType().getText());
            currencyType.setCurrSymbol("currency");

            monetaryValueType.setId(uniqueIDGenerator.nextId());
            monetaryValueType.setmValue(Double.parseDouble(ctx.value().monetaryValueType().mValue().getText()));
            monetaryValueType.setCurrency(currencyType);

            asset.setMonetaryValueType(monetaryValueType);
            asset.setAssetID(uniqueIDGenerator.nextId());
            asset.setOwner(uniqueIDGenerator.nextId());
            asset.setSamID(uniqueIDGenerator.nextId());
            assetService.insert(asset);

Whenever I call the class mentioned above, I get the following error:

Hibernate: 
    insert 
    into
        element1
        (datefrom, dateto, description, name, statusid, samid) 
    values
        (?, ?, ?, ?, ?, ?)
2019-08-05 20:19:00 INFO  MyClass:63 - the result is:true
Hibernate: 
    select
        monetaryva_.mvid,
        monetaryva_.currency_id as currency3_57_,
        monetaryva_.m_value as m_value2_57_ 
    from
        monetaryvaluetype monetaryva_ 
    where
        monetaryva_.mvid=?
2019-08-05 20:19:01.084  WARN 56712 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1054, SQLState: 42S22
2019-08-05 20:19:01.084 ERROR 56712 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : Unknown column 'monetaryva_.currency_id' in 'field list'

As you can see, hibernate created columns (currency_id instead of currencyID) that are not in accordance with my database tables even though I used the @Column annotation.

Upvotes: 0

Views: 668

Answers (1)

Amol Kachale
Amol Kachale

Reputation: 36

Use following two lines in your application.properties file

spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

Upvotes: 2

Related Questions