Как использовать время Joda с JPA (eclipselink)?

Я попытался использовать DataTime в моем классе entity. Добавив @Temporal(TemporalType.DATE) над полем, я получил сообщение об ошибке "Постоянное поле или свойство типа Temporal должно быть типа java.util.Date, java.util.Calendar или java.util.GregorianCalendar" . Я могу ввести конверсию туда и обратно; используя сеттеры и геттеры следующим образом:

@Temporal(TemporalType.DATE)
private Calendar attendanceDate;

public DateTime getAttendanceDate() {
    return new DateTime(this.attendanceDate);
}

public void setAttendanceDate(DateTime attendanceDate) {
    this.attendanceDate = attendanceDate.toCalendar(Locale.getDefault());
}

но я надеюсь eclipselink сделать это для меня. Я ушел в прошлое Переносить DateTime в Joda-time через Hibernate. Ответ, предлагающий использовать спящий режим, но я должен использовать eclipselink. Я могу использовать объект DateTime в классе сущности с представлением БД как BLOB, но мне это нужно как Date. Есть что-нибудь вроде jodatime-eclipselink? Или любое другое предложение? Спасибо за помощь.

Ответы

Ответ 1

Базовая ссылка определяет конвертер EclipseLink для преобразования из Joda DateTime в java.sql.Timestamp или Date. Вы можете использовать его или определить свой собственный конвертер и использовать его через @Convert, @Converter в EclipseLink.

Для создания DDL конвертер должен определить метод initialize и задать тип в поле сопоставления java.sql.Timestamp.

Пожалуйста, зарегистрируйте ошибку (или голосуйте за существующую) на этом в EclipseLink, мы должны поддерживать Joda.

Ответ 2

Я пытаюсь использовать joda-time-eclipselink-integration, но не работает, вероятно, я сделал что-то неправильно,

Итак, я сделал больше исследований, и я нашел эту ссылку http://jcodehelp.blogspot.com.br/2011/12/persist-joda-datetime-with-eclipselink.html, они используют аннотацию @Converter для преобразования времени даты Joda.

Я стараюсь и работаю для меня, надеюсь, тоже работает для вас.

Ответ 3

Я хотел сделать то же самое, и Googling вокруг фактически привел меня сюда. Я смог выполнить это, используя аннотацию @Access. Во-первых, вы комментируете класс, подобный этому

@Access(AccessType.FIELD)
public class MyClass
{
    ....

Это обеспечивает доступ ко всем полям, поэтому вам не нужно отдельно аннотировать поля. Затем вы создаете getter и setter для использования JPA.

@Column(name="my_date")
@Temporal(TemporalType.DATE)
@Access(AccessType.PROPERTY)
private Date getMyDateForDB()
{
    return myDate.toDate();
}

private void setMyDateForDB(Date myDateFromDB)
{
    myDate = new LocalDate(myDateFromDB);
}

@Access(AccessType.PROPERTY) указывает JPA на сохранение и извлечение данных с помощью этих методов.

Наконец, вы захотите пометить переменную-член как переходную, как показано ниже.

@Transient
private LocalDate myDate = null;

Это останавливает попытку JPA также сохранить поле.

Это должно выполнить то, что вы пытаетесь сделать. Это отлично поработало для меня.

Ответ 4

Ахмед, ты сказал, что это не работает для тебя. Кроме того, вам необходимо переопределить метод инициализации конвертера, чтобы определить желаемый тип поля:

@Override
public void initialize(DatabaseMapping mapping, Session session) {
    ((AbstractDirectMapping) mapping)
            .setFieldClassification(java.sql.Timestamp.class);
}

Ответ 5

Ниже приведен рабочий пример, основанный на ответах, доступных в теме

В основном самый простой подход - использовать EclipseLink @Converter для поля DateTime в вашем Entity.

Использование конвертера выглядит следующим образом:

import org.eclipse.persistence.annotations.Convert;
import org.eclipse.persistence.annotations.Converter;
import javax.persistence.*;
import org.joda.time.DateTime;

@Entity
public class YourEntity {

    @Converter(name = "dateTimeConverter", converterClass = your.package.to.JodaDateTimeConverter.class)
    @Convert("dateTimeConverter")
    private DateTime date;

И сам конвертер:

import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.converters.Converter;
import org.eclipse.persistence.sessions.Session;
import org.joda.time.DateTime;
import java.sql.Timestamp;

public class JodaDateTimeConverter implements Converter {

    private static final long serialVersionUID = 1L;

    @Override
    public Object convertDataValueToObjectValue(Object dataValue, Session session) {
        return dataValue == null ? null : new DateTime(dataValue);
    }

    @Override
    public Object convertObjectValueToDataValue(Object objectValue, Session session) {
        return objectValue == null ? null : new Timestamp(((DateTime) objectValue).getMillis());
    }

    @Override
    public void initialize(DatabaseMapping mapping, Session session) {
         // this method can be empty if you are not creating DB from Entity classes 
         mapping.getField().setType(java.sql.Timestamp.class);
    }

    @Override
    public boolean isMutable() {
        return false;
    }

}

Я добавляю это для упрощения копирования и вставки.

Ответ 7

Ответ от Atais работает хорошо. Ниже обновления до него.

Вы можете опустить аннотацию @converter, зарегистрировав ее по всему миру. На persistance.xml в persitence-unit добавьте:

<mapping-file>META-INF/xyz-orm.xml</mapping-file>

и файл META-INF/xyz-orm.xml с контентом:

<?xml version="1.0"?>
<entity-mappings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm" version="2.1">
    <converter class="pl.ds.wsc.storage.converter.JodaDateTimeConverter"/>
</entity-mappings>

Если ваш конфигурационный файл META-INF/orm.xml, вы можете опустить даже первый шаг, потому что он по умолчанию используется для всех единиц времени.