用于持久保存以枚举类型作为键的 Map 的 Hibernate 注释是什么?

发布于 2024-09-01 12:34:21 字数 1691 浏览 2 评论 0原文

我在获取正确的休眠注释以在以枚举类作为键的地图上使用时遇到困难。这是一个简化的(并且极其人为的)示例。

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 尝试将 letter(我的映射键)定义为tinyblob,但是它将 startLetter 定义为 varchar(255),尽管两者都是枚举类型 Letter。当我尝试创建表时,我看到以下错误

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

,我在 google 上搜索了此错误,当您尝试将tinyblob列作为主键的一部分时,MySql 似乎出现了问题,这就是 hibernate 需要对 Thing_letterFrequencies 表执行的操作。所以我宁愿将字母映射到 varchar(255),就像 startLetter 那样。

不幸的是,我已经对 MapKey 注释大惊小怪了一段时间了,但无法完成这项工作。我也尝试过 @MapKeyManyToMany(targetEntity=Product.class) 但没有成功。谁能告诉我 letterCounts 映射的正确注释是什么,以便 hibernate 将以与 startLetter 相同的方式处理 letterCounts 映射键?

I am having trouble getting the right hibernate annotations to use on a Map with an enumerated class as a key. Here is a simplified (and extremely contrived) example.

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
}

Here are my current annotations on 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 generates the following DDL to create the tables for my MySql database

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;

Notice that hibernate tries to define letter (my map key) as a tinyblob, however it defines startLetter as a varchar(255) even though both are of the enumerated type Letter. When I try to create the tables I see the following error

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

I googled this error and it appears that MySql has issues when you try to make a tinyblob column part of a primary key, which is what hibernate needs to do with the Thing_letterFrequencies table. So I would rather have letter mapped to a varchar(255) the way startLetter is.

Unfortunately, I've been fussing with the MapKey annotation for a while now and haven't been able to make this work. I've also tried @MapKeyManyToMany(targetEntity=Product.class) without success. Can anyone tell me what are the correct annotations for my letterCounts map so that hibernate will treat the letterCounts map key the same way it does startLetter?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

醉城メ夜风 2024-09-08 12:34:21

我发现了一些适用于 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 这样的神奇数字,我想听听。

I found something that works on https://forum.hibernate.org/viewtopic.php?f=1&t=999270&start=0 although it is kind of ugly. If you assume that Letter is in the com.myexample package here are the annotations

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

Note the @Parameter(name="type", value="12") Apparently the "value=12" maps the enumerated type to a varchar. Hopefully this helps someone else out but if anyone has a cleaner annotation without the use of magic numbers like 12 I want to hear it.

回忆凄美了谁 2024-09-08 12:34:21

如果您使用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;

If you use java6, you may try to use @MapKeyEnumerated (javax.persistence) annotation instead of @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:

Whole class code (using 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>();
}

What hibernate generates in MySQL (create table statements):

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文