Как молча обрезать строки при их хранении, когда они длиннее определения длины столбца? - PullRequest
33 голосов
/ 04 октября 2011

У меня есть веб-приложение, использующее EclipseLink и MySQL для хранения данных. Некоторые из этих данных являются строками, т.е. varchars в БД. В коде сущностей строки имеют такие атрибуты:

@Column(name = "MODEL", nullable = true, length = 256)
private String model;

База данных не создается eclipseLink из кода, но длина соответствует длине varchar в БД. Когда длина таких строковых данных больше, чем атрибут длины, возникает исключение во время вызова javax.persistence.EntityTransaction.commit ():

javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.1.0.v20100614-r7608): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'MODEL' at row 1

Затем транзакция откатывается. Хотя я понимаю, что это поведение по умолчанию, это не то, что я хочу. Я хотел бы, чтобы данные были беззвучно обрезаны, а транзакция зафиксирована.

Могу ли я сделать это, не добавляя вызов подстроки в каждый метод набора строковых данных для соответствующих объектов?

Ответы [ 12 ]

0 голосов
/ 19 апреля 2018

Был уже ответ упомянутых конвертеров , но я хочу добавить больше деталей.Мой ответ также предполагает преобразователи из JPA, а не специфичные для EclipseLink.

Сначала создайте этот класс - специальный преобразователь типов, в обязанности которого входит усечение значения в момент сохранения:

import javax.persistence.AttributeConverter;
import javax.persistence.Convert;

@Convert
public class TruncatedStringConverter implements AttributeConverter<String, String> {
  private static final int LIMIT = 999;

  @Override
  public String convertToDatabaseColumn(String attribute) {
    if (attribute == null) {
      return null;
    } else if (attribute.length() > LIMIT) {
      return attribute.substring(0, LIMIT);
    } else {
      return attribute;
    }
  }

  @Override
  public String convertToEntityAttribute(String dbData) {
    return dbData;
  }
}

Затем выВы можете использовать его в своих организациях следующим образом:

@Entity(name = "PersonTable")
public class MyEntity {
    
    @Convert(converter = TruncatedStringConverter.class)
    private String veryLongValueThatNeedToBeTruncated;
 
    //...
}

Статья по теме о конвертерах JPA: http://www.baeldung.com/jpa-attribute-converters

0 голосов
/ 14 февраля 2018

Другой вариант - объявить константу и ссылаться на нее везде, где вам нужна эта длина, начиная с самой аннотации @Column.

Эта константа может быть затем передана в функцию усечения или функцию проверки, которая выдает предупреждающее исключение, если переданная строка слишком длинная. Эта константа также может быть повторно использована на некоторых других уровнях, таких как пользовательский интерфейс.

Например:

@Entity
public class MyEntity {
    public static final int NAME_LENGTH=32;

    private Long id;
    private String name;

    @Id @GeneratedValue
    public Long getId() {
        return id;
    }
    protected void setId(Long id) {
        this.id = id;
    }

    @Column(length=NAME_LENGTH)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = JpaUtil.truncate(name, NAME_LENGTH);
    }
}

public class JpaUtil {
    public static String truncate(String value, int length) {
        return value != null && value.length() > length ? value.substring(0, length) : value;
    }
}
...