1

I got a legacy database which I want to keep as it is, but this causes some problems with hibernate.

My current problem is, that I have the field private Calendar myTradeDateTime; in my POJO and this is mapped to 2 columns.

The first column holds only the date information (e.g. '2013-05-14') and the second column holds only the time information (e.g. '10:09:12 PM'). Now I want to use hibernate to access both columns with just that 1 field. I would assume that I need some @Converter to deal with it, but I have no idea how that should be done and I couldn't find any info on this topic (2 columns into 1 field).

So my question is, how can I map 2 columns into 1 field in hibernate 5.3?

4 Answers 4

3

As I explained in this article, JPA and Hibernate map each entity attribute to a database column. But you can use a small workaround to achieve the requested mapping.

You first need 2 entity attributes that map the 2 database columns. If you use field-based access (you annotate the attributes and not the setters), you can skip the getter and setter methods for these attributes. You can then add a 3rd attribute, which is the one you will use in your business code. You need to annotate it with @Transient and calculate its value based on the other 2 attributes.

Here's a mapping that uses this approach to map a time (postedAtTime) and a date (postedAtDate) column to the LocalDateTime postedAt attribute.

@Entity
public class Review {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String comment;

    private LocalDate postedAtDate;

    private LocalTime postedAtTime;

    @Transient
    private LocalDateTime postedAt;

    public Long getId() {
        return id;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public LocalDateTime getPostedAt() {
        if (postedAt == null) {
            this.postedAt = LocalDateTime.of(this.postedAtDate, this.postedAtTime);
        }
        return postedAt;
    }

    public void setPostedAt(LocalDateTime postedAt) {
        this.postedAt = postedAt;
        this.postedAtDate = postedAt.toLocalDate();
        this.postedAtTime = postedAt.toLocalTime();
    }
}

Please be aware, that you need to use the postedAtDate and postedAtTime attributes in your JPQL And Criteria queries. But as long as you work with the Review entity object, you don't need to know about these 2 internal attributes.

Sign up to request clarification or add additional context in comments.

Comments

2

When you use hibernate native API and hbm.xml it still works like that:

    <property name="dateMitUltimo" type="org.UTDateUltimo">
        <column name="DAT_ULTIMO" />
        <column name="SL_ULTIMO" />
    </property>

With UserType like that:

public class UTDateUltimo
    implements CompositeUserType {

Using the JPA-API of hibernate this no longer works :-( Instead you can try the embedded feature. In xml this looks like:

<entity class="de.parcit.base.db.jpa.TestEmbedded" name="TestEmbedded">
    <table name="TEMBED" />

    <attributes>
        <!-- domain="ID" type="long" -->
        <id name="id" type="long">
            <!-- <generated-value strategy="TABLE" /> -->
        </id>

        <embedded name="dateMitUltimo" />

    </attributes>
</entity>

<embeddable class="de.parcit.base.db.jpa.DateJPA" access="FIELD">

    <convert converter="de.parcit.base.db.jpa.DateConverter" attribute-name="date" />

    <attributes>

        <!-- domain="Datum_Ultimo" -->
        <basic name="date">
            <column name="DAT_ULTIMO" />
        </basic>

        <!-- domain="SL_SI" -->
        <basic name="month">
            <column name="SL_ULTIMO" />
        </basic>
    </attributes>
</embeddable>

and

public class DateConverter
    implements AttributeConverter<Date, java.sql.Date> {

I didnt try this with annotations.

Update:

"embedded" can be used with annotations too. Here is an example: Java - JPA @Basic and @Embedded annotations

Comments

0

I think there is no way to do such thing in Hibernate. I suggest to map both columns and create a getter and setter as you could see below (In addition of those you already have to create):

private LocalDate tradeDate;
private LocalTime tradeTime;

and a get/set method like:

public Calendar getMyTradeDateTime(){
    LocalDateTime dateTime = LocalDateTime.of(this.tradeDate, this.tradeTime);
    Calendar c = Calendar.getInstance();
    return c.setTimeInMillis(dateTime.toEpochSecond(ZoneOffset.of("-03:00"))*1000);
}

PS: To set the zoneoffset of your VM timezone. Can get it programmatically(?).

public void setMyTradeDateTime(Calendar c) {
   LocalDateTime dateTime = LocalDateTime.ofInstant(c.toInstant(), ZoneId.systemDefault());
    this.tradeDate = dateTime.toLocalDate();
    this.tradeTime = dateTime.toLocalTime();
}

Comments

-1
@Entity
public class Review {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String comment;

    private LocalDate postedAtDate;

    private LocalTime postedAtTime;

    @Transient
    private LocalDateTime postedAt;

    public Long getId() {
        return id;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public LocalDateTime getPostedAt() {
        if (postedAt == null) {
            this.postedAt = LocalDateTime.of(this.postedAtDate, this.postedAtTime);
        }
        return postedAt;
    }

    public void setPostedAt(LocalDateTime postedAt) {
        this.postedAt = postedAt;
        this.postedAtDate = postedAt.toLocalDate();
        this.postedAtTime = postedAt.toLocalTime();
    }
}

1 Comment

When answering an old question, your answer would be much more useful to other StackOverflow users if you included some context to explain how your answer helps. See: How do I write a good answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.