Pergunta

Eu estou usando Hibernate como meu provedor de JPA com ele se conectar a um banco de dados Progress. Quando um valor NaN é mantido ele está causando muitos problemas - que impede a linha de ser lido em determinadas circunstâncias. Existe uma maneira de ligar para o duplo padrão Tipo de persistência para converter NaN (e provavelmente + e - infinito) para um valor diferente? Não importa se a informação NaN ou infinito é perdido, eu só quero uma linha legível!

Eu sei que eu poderia fazer algo parecido com isto:

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

Mas eu estou preocupado sobre a manutenção como que terá de ser adicionado manualmente para quaisquer duplas mapeados para o banco de dados.

Foi útil?

Solução

A minha primeira impressão deste seria a de olhar para o tipo que o Hibernate persiste double como. Assim, você pode refatorar o método set(...) em DoubleType . Isso significa porém que você precisa anotar cada tipo Double com @org.hibernate.annotations.type(type="myDouble") depois de ter definido "myDouble" usando @org.hibernate.annotations.TypeDef no pacote-info - Eu acho que você quer evitar tudo isso para manutenção (para além de que você teria que ir para o coração do Hibernate).

Outras dicas

Você pode modificar hibernar si. Tudo que você tem a fazer é mudar o DoubleType classe.

É claro, você então tem que manter esse patch como evolui de hibernação, mas considerando que é em uma única classe, bastante estável isso pode ser mais fácil do que a especificação de um UserType para cada dupla em seu modelo de domínio.

Após essa discussão , tenho a sensação de que hibernate não oferece uma maneira de converter NaN em outra coisa. Eu acho que, você tem que evitar que valores NaN mais cedo, mesmo antes de serem escritos para as variáveis ??de membro de feijão (como a adição de código de guarda / conversão para os setters).

Editar

temo, a melhor solução desagradável é usar código de guarda e, o que é ainda pior, uma coluna adicional na tabela, a bandeira, se o valor for um número ou não. O que certamente vai complicar as operações de consulta e de inserção. Mas você precisa de NaN no banco de dados e você não pode lutar contra o driver JDBC / banco de dados para comportar corretamente (e aceito NaN como entradas válidas para campos de número).

Eu usei a solução UserType no final, mas resolveu o problema de manutenção com um teste de unidade. A classe tipo é o seguinte:

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);
    }
}

O teste de unidade é mais ou menos (alguns detalhes removido por brevidade):

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);
        }
    }
}

Eu tinha exatamente o mesmo problema, e com a orientação destas soluções, eu também preparou uma classe tipo personalizado estendendo DoubleType. Dentro dessa classe I convertido valores NaN para NULL na função set e vice-versa para a função get, desde nula é OK para minhas colunas de banco de dados. Também mudei o mapeamento para NaN possíveis colunas para a classe tipo personalizado. Essa solução funcionou perfeitamente para hibernate 3.3.2.

Infelizmente, após a atualização Hibernate para 3.6.10, ele parou de funcionar. A fim de fazê-lo funcionar de novo, eu substituiu o tipo personalizado de estender DoubleType para implementar UserType.

Os importantes implementações de função de tipo de dados deve ser a seguinte:

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

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

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

E aqui estão as funções get e 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);
}

Lamentamos, mas a julgar por seus exemplos e sua pergunta você realmente tem problemas em entender Java Persistence. Database-entidades são auto-gerenciados via getters e setters - estes podem fazer qualquer validação que você gostaria que eles têm. Se você realmente definir atributos sem eles, você está perdendo conceitos fundamentais do desenvolvimento e persistência orientadas a objetos - entidades geridas em particular. Parece-me que você precisa re-projetar seu projeto, ter problemas como estes são um sinal claro de falhas de design fundamentais ... apenas dando alguns conselhos aqui - e isso é a solução:

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

.... sua tão fácil.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top