Какие аннотации гибернации используются для сохранения карты с перечислимым типом в качестве ключа? - PullRequest
1 голос
/ 16 мая 2010

У меня проблемы с получением нужных спящих аннотаций для использования на карте с перечисленным классом в качестве ключа. Вот упрощенный (и чрезвычайно надуманный) пример.

public class Thing {
    public String id;
    public Letter startLetter;
    public Map<Letter,Double> letterCounts = new HashMap<Letter, Double>(); 
}


public enum Letter {
    A,
    B,
    C,
    D
}

Вот мои текущие аннотации на Thing

@Entity
public class Thing {

    @Id
    public String id;

    @Enumerated(EnumType.STRING)
    public Letter startLetter;

    @CollectionOfElements
    @JoinTable(name = "Thing_letterFrequencies", joinColumns = @JoinColumn(name = "thingId"))
    @MapKey(columns = @Column(name = "letter", nullable = false))
    @Column(name = "count")
    public Map<Letter,Double> letterCounts = new HashMap<Letter, Double>();

}

Hibernate генерирует следующий DDL для создания таблиц для моей базы данных MySql

create table Thing (id varchar(255) not null, startLetter varchar(255), primary key (id)) type=InnoDB;
create table Thing_letterFrequencies (thingId varchar(255) not null, count double precision, letter tinyblob not null, primary key (thingId, letter)) type=InnoDB;

Обратите внимание, что hibernate пытается определить букву (мой ключ карты) как крошечный шарик, однако он определяет startLetter как varchar (255), даже если оба имеют перечислимый тип Letter. Когда я пытаюсь создать таблицы, я вижу следующую ошибку

BLOB/TEXT column 'letter' used in key specification without a key length

Я погуглил эту ошибку, и кажется, что у MySql есть проблемы, когда вы пытаетесь сделать столбец tinyblob частью первичного ключа, а именно это нужно hibernate с таблицей Thing_letterFrequencies. Поэтому я бы предпочел, чтобы письмо было сопоставлено с varchar (255), как startLetter.

К сожалению, я некоторое время возился с аннотацией MapKey и не смог сделать эту работу. Я также попытался @MapKeyManyToMany (targetEntity = Product.class) без успеха. Может кто-нибудь сказать мне, каковы правильные аннотации для моей карты letterCounts, чтобы hibernate обрабатывал ключ карты letterCounts так же, как и startLetter?

Ответы [ 2 ]

0 голосов
/ 17 мая 2010

Я нашел что-то, что работает на https://forum.hibernate.org/viewtopic.php?f=1&t=999270&start=0, хотя это немного уродливо. Если вы предполагаете, что Letter находится в пакете com.myexample, аннотации

@CollectionOfElements
@JoinTable(name = "Thing_letterFrequencies", joinColumns = @JoinColumn(name = "thingId"))
@MapKey(columns = @Column(name = "letter"),
    type = @Type(
      type="org.hibernate.type.EnumType",
      parameters = {@Parameter(name = "enumClass", value="com.myexample.Letter"), @Parameter(name="type", value="12")}
    ))
@Column(name = "count")
public Map<Letter,Double> letterCounts = new HashMap<Letter, Double>();

Обратите внимание на @Parameter (name = "type", value = "12"). Очевидно, "value = 12" отображает перечислимый тип в varchar. Надеюсь, это поможет кому-то еще, но если у кого-то есть более чистая аннотация без использования магических чисел, таких как 12, я хочу услышать это.

0 голосов
/ 16 мая 2010

Если вы используете java6, вы можете попробовать использовать аннотацию @MapKeyEnumerated (javax.persistence) вместо @ MapKey

@ElementCollection
    @JoinTable(name = "thing_letter_frequencies", joinColumns = @JoinColumn(name = "thing_id"))
    @MapKeyEnumerated(EnumType.STRING)
    @Column(name = "letter_count")
    public Map<Letter, Double> letterCount = new HashMap<Letter, Double>();

UPDATE:

Весь код класса (с использованием Project Lombok)

@Entity
public class Thing {

    @Getter
    @Setter
    @Id
    private String id;

    @Getter
    @Setter
    @Enumerated(EnumType.STRING)
    private Letter startLetter;

    @Getter
    @Setter
    @ElementCollection
    @JoinTable(name = "thing_letter_frequencies", joinColumns = @JoinColumn(name = "thing_id"))
    @MapKeyEnumerated(EnumType.STRING)
    @Column(name = "letter_count")
    public Map<Letter, Double> letterCount = new HashMap<Letter, Double>();
}

Что генерирует hibernate в MySQL (создание операторов таблицы):

CREATE TABLE `thing` (
    `id` VARCHAR(255) NOT NULL,
    `startLetter` VARCHAR(255) NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
)
ENGINE=InnoDB
ROW_FORMAT=DEFAULT;

CREATE TABLE `thing_letter_frequencies` (
    `thing_id` VARCHAR(255) NOT NULL,
    `letter_count` DOUBLE NULL DEFAULT NULL,
    `letterCount_KEY` VARCHAR(255) NOT NULL DEFAULT '',
    PRIMARY KEY (`thing_id`, `letterCount_KEY`),
    INDEX `FKA0A7775246D72F41` (`thing_id`),
    CONSTRAINT `FKA0A7775246D72F41` FOREIGN KEY (`thing_id`) REFERENCES `thing` (`id`)
)
ENGINE=InnoDB
ROW_FORMAT=DEFAULT;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...