You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate:如何持久化以Question对象为键的HashMap?

Hey there! Mapping a HashMap with an entity as the key and polymorphic values (either Integer or an Answer entity) in Hibernate is totally doable, but it requires handling two specific challenges: using an entity as the map key and supporting multiple value types. Let's walk through exactly how to set this up.

Step 1: Prepare Your Entity Classes

First, make sure your Question and Answer entities are properly annotated (if you're using Answer as a value type):

Question Entity

@Entity
public class Question {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String questionText;
    // Add other fields like options, difficulty, etc.

    // Critical: Implement equals() and hashCode() based on the ID
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Question)) return false;
        Question question = (Question) o;
        return Objects.equals(id, question.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    // Getters and Setters
}

Answer Entity (if using as a value type)

@Entity
public class Answer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String answerText;
    // Add other relevant fields

    // Getters and Setters
}

Step 2: Map the Polymorphic HashMap in the User Entity

The core work happens in your User class. We'll use Hibernate's @Any annotation to handle the polymorphic values, and @MapKeyJoinColumn to map the Question entity as the map key.

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;

    // The polymorphic HashMap mapping
    @ElementCollection
    @CollectionTable(
        name = "user_question_answers",
        joinColumns = @JoinColumn(name = "user_id")
    )
    @MapKeyJoinColumn(name = "question_id") // Maps Question entity to the 'question_id' column
    @Any(metaColumn = @Column(name = "answer_type"))
    @AnyMetaDef(
        idType = "long",
        metaType = "string",
        metaValues = {
            @MetaValue(targetEntity = Integer.class, value = "INT"),
            @MetaValue(targetEntity = Answer.class, value = "ANSWER")
        }
    )
    @Column(name = "answer_int_value") // Stores Integer answers
    @JoinColumn(name = "answer_id") // Stores foreign key to Answer entity
    private Map<Question, Object> questionAnswers = new HashMap<>();

    // Getters and Setters
}

Let's Break Down the Annotations

  • @ElementCollection: Tells Hibernate this is a collection of non-entity values (or polymorphic values) associated with the User. It will create a separate join table (user_question_answers) to store these mappings.
  • @CollectionTable: Defines the name of the join table and the foreign key linking back to the User table.
  • @MapKeyJoinColumn: Specifies that the map's key is the Question entity, and it will store the Question's ID in the question_id column of the join table.
  • @Any: Enables polymorphic mapping for the map's value. The metaColumn stores a string identifier to distinguish between Integer and Answer values.
  • @AnyMetaDef: Maps the string identifiers from metaColumn to actual types. Here, "INT" maps to Integer.class, and "ANSWER" maps to Answer.class. The idType specifies the data type used to store the value (both Integer and Answer's ID use long).
  • @Column and @JoinColumn: These define the columns that store the actual values. For Integer answers, the value goes into answer_int_value; for Answer entities, we store the foreign key in answer_id. One of these columns will be null for each row, depending on the value type.

Important Notes

  1. equals() and hashCode() for Question: Since Question is used as a HashMap key, you must implement equals() and hashCode() based on its persistent ID (not transient state). This ensures Hibernate can correctly manage the map keys.
  2. Type Casting: When retrieving values from the map, you'll need to cast them to the appropriate type:
    // Get an Integer answer
    Integer intAnswer = (Integer) user.getQuestionAnswers().get(someQuestion);
    // Get an Answer entity
    Answer entityAnswer = (Answer) user.getQuestionAnswers().get(anotherQuestion);
    
  3. Database Table Setup: The user_question_answers table will need nullable columns for answer_int_value and answer_id, since only one will be populated per row.
  4. Alternative: Split the Map: If your use case allows, splitting into two separate maps (one for Integer answers, one for Answer entities) simplifies mapping (using standard @ElementCollection with @MapKeyJoinColumn for each). But if you need a single map, the above approach works.

内容的提问来源于stack exchange,提问作者William Toscano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:59:35