문제

최대 절전 모드를 JPA 제공 업체로 사용하여 진행 데이터베이스에 연결하고 있습니다. NAN 값이 지속되면 많은 문제가 발생합니다. 특정 상황에서 행이 읽히는 것을 방지합니다. 표준 이중 유형 지속성에 연결하여 NAN (및 아마도 + 및 - 인피니티)을 다른 값으로 변환 할 수있는 방법이 있습니까? NAN 또는 Infinity 정보가 손실되었는지 여부는 중요하지 않습니다. 단지 읽을 수있는 행을 원합니다!

나는 다음과 같이 할 수 있다는 것을 안다.

@Column(name = "doubleColumn")
public double getDoubleColumn() {
    return PersistedDouble.convert(doubleColumn);
}

그러나 데이터베이스에 맵핑 된 두 배에 대해 수동으로 추가해야하기 때문에 유지 보수가 걱정됩니다.

도움이 되었습니까?

해결책

이것에 대한 나의 첫 인상은 최대 절전 모드가 지속되는 유형을 찾는 것입니다. double 처럼. 그래서 당신은 다음을 리팩터 할 수 있습니다 set(...) 방법 DoubleType. 그것은 당신이 매번 주석을 달아야한다는 것을 의미합니다. Double 유형 @org.hibernate.annotations.type(type="myDouble") "MyDouble"사용을 정의한 후 @org.hibernate.annotations.TypeDef Package-Info에서-나는 당신이 유지를 위해이 모든 것을 피하고 싶다고 생각합니다 (당신은 최대 절전 모드의 중심으로 가야한다는 것 외에는).

다른 팁

최대 절전 모드 자체를 수정할 수 있습니다. 클래스 이중화 유형을 변경하기 만하면됩니다.

물론, 당신은 해당 패치를 최대 절전 모드로 유지해야하지만, 단일의 안정적인 클래스라는 점을 고려하면 도메인 모델의 모든 두 배에 대해 사용자 유형을 지정하는 것보다 쉬울 수 있습니다.

이 토론 후, 최대 절전 모드는 NAN을 다른 것으로 바꾸는 방법을 제공하지 않는다는 느낌이 있습니다. NAN 값이 Bean 멤버 변수에 기록되기 전에도 (세터에 가드/변환 코드를 추가하는 등) 더 일찍 방지해야한다고 생각합니다.

편집하다

최고의 불쾌한 솔루션은 가드 코드를 사용하는 것이며, 이는 값이 숫자인지 아닌지에 관계없이 테이블의 추가 열이 더 나쁜 것입니다. 확실히 쿼리 및 삽입 작업을 복잡하게 할 것입니다. 그러나 데이터베이스에 NAN이 필요하며 JDBC 드라이버/데이터베이스와 싸우기 위해 제대로 작동하고 NAN을 숫자 필드에 대한 유효한 입력으로 받아 들일 수 없습니다.

결국 사용자 유형 솔루션을 사용했지만 단위 테스트로 유지 보수 문제를 해결했습니다. 유형 클래스는 다음과 같습니다.

public class ParsedDoubleType extends DoubleType {
    private static final long serialVersionUID = 1L;

    @Override
    public void set(PreparedStatement st, Object value, int index) throws SQLException {
        Double doubleValue = (Double) value;
        if (doubleValue.isInfinite() || doubleValue.isNaN()) {
            Logger.getLogger(ParsedDoubleType.class).warn("Attempted to send a NaN or infinity value to the database " 
                + "- this is not supported.\nStatement=" + st + " valueIndex=" + index);
            doubleValue = Double.valueOf(0);
        }
        super.set(st, doubleValue, index);
    }
}

단위 테스트는 대략적으로 (간결성을 위해 제거 된 일부 세부 사항) :

Ejb3Configuration hibernateConfig = new Ejb3Configuration().configure("InMemoryDatabasePersistenceUnit", null);
for (Iterator<?> iterator = hibernateConfig.getClassMappings(); iterator.hasNext();) {
    PersistentClass clazz = (PersistentClass) iterator.next();
    Iterator<?> propertyIterator = clazz.getPropertyIterator();
    while (propertyIterator.hasNext()) {
        if (property.getType().equals(Hibernate.DOUBLE)) {
            Assert.fail("Raw double type found. Annotate with @Type(type = \"package.ParsedDoubleType\")\n" 
                + "Class " + clazz + " property " + property);
        }
    }
}

나는 정확히 같은 문제를 겪었고 이러한 솔루션의 지침으로 DoubleType을 확장하는 사용자 정의 유형 클래스도 준비했습니다. 해당 클래스 내에서는 NUL이 데이터베이스 열에 대해 괜찮으므로 NAN 값을 설정 함수에서 NULL로 변환하고 GET 기능의 경우도 마찬가지입니다. 또한 NAN 가능한 열의 매핑을 사용자 정의 유형 클래스로 변경했습니다. 이 솔루션은 최대 절전 모드 3.3.2에 완벽하게 작용했습니다.

불행히도, 최대 절전 모드를 3.6.10으로 업그레이드 한 후 작동이 멈췄습니다. 다시 작동하기 위해 DoubleType를 확장하여 사용자 유형을 구현하는 것에서 사용자 정의 유형을 대체했습니다.

중요한 데이터 유형 기능 구현은 다음과 같습니다.

private int[] types = { Types.DOUBLE };

public int[] sqlTypes()
{
    return types;
}

@SuppressWarnings("rawtypes")
public Class returnedClass()
{
    return Double.class;
}

그리고 다음은 Get and Set 기능입니다.

public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException
{
    Double value = rs.getDouble(names[0]);
    if (rs.wasNull())
        return Double.NaN;
    else
        return value;
}

public void nullSafeSet(PreparedStatement ps, Object value, int index) throws HibernateException, SQLException
{
    Double dbl = (Double) value;
    if ((dbl == null) || (Double.isNaN(dbl)))
        ps.setNull(index, Types.DOUBLE);
    else
        ps.setDouble(index, dbl);
}

죄송하지만 예제와 질문에서 판단하면 실제로 Java 지속성을 이해하는 데 문제가 있습니다. 데이터베이스 엔티티는 게터와 세터를 통해 자체 관리됩니다. 이들은 원하는 검증을 수행 할 수 있습니다. 당신이 그들없이 속성을 실제로 설정했다면, 객체 지향 개발 및 지속성, 특히 관리 엔티티의 핵심 개념이 누락되었습니다. Methinks 프로젝트를 다시 엔지니어링해야합니다. 이와 같은 문제가있는 기본 디자인 결함의 확실한 신호입니다. 여기에 조언을 제공합니다.

@Column(name="doubleColumn"}
private Double doubleColumn = Double.NaN  //yes, this is intentional. Verily.

public void setDouble(Double d)
{
    if(d.isNan || d.isInfinite()
    {
       //do something nice here
    }
    else
       this.doubleColumn = d;
}
public Double getDouble()
{
   return !this.doubleColumn.isNaN() && !this.doubleColumn.isInfinite() ? this.doubleColumn : new Double();
}

.... 그게 쉽습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top