Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HIbernate OneToMany FetchType.EAGER not returning values

I use Hibernate 3.5.6 and MySQL 5.1. I have 3 classes: Item, Attribute, AttributeValue. They relate to each other with a One-to-Many relationship, and I do get all Attributes for a given Item. But I don't get AttributeValues for a given Attribute. I cannot see exceptions or errors, and data in the tables looks good, meaning that insertion of the data went well.

I have tried different strategies for FetchMode of Attribute's map of AttributeValues, but result is always empty.

What have I missed?

Here are the classes:

@Entity
@Table(name = "Item")
public class Item implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private String serialNumber;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "item", cascade = CascadeType.ALL)
    @Fetch(value = FetchMode.SELECT)    // don't remove this line
    @MapKey(name = "name")
    private Map<String, Attribute> attributes = new HashMap<String, Attribute>();

    protected Item() {
        super();
    }

    public Item(String serialNumber) {
        this();
        setSerialNumber(serialNumber);
    }

    public String getSerialNumber() {
        return serialNumber;
    }

    protected void setSerialNumber(String serialNumber) {
        this.serialNumber = serialNumber;
    }

    public Map<String, Attribute> getAttributes() {
        return attributes;
    }

    public void setAttributes(Map<String, Attribute> attributes) {
        this.attributes = attributes;
    }
}

@Entity
@Table(name = "Attribute", uniqueConstraints = {@UniqueConstraint(columnNames = {"item_serialNumber", "name"})})
public class Attribute implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @ManyToOne(cascade = CascadeType.ALL)
    private Item item;

    @Column(nullable = false)
    private String name;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "value", cascade = CascadeType.ALL)
    @Fetch(value = FetchMode.SELECT)
    @MapKey(name = "value")
    private Map<String, AttributeValue> values = new HashMap<String, AttributeValue>();

    protected Attribute() {
        super();
    }

    public Attribute(String name) {
        super();
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    protected void setId(Integer id) {
        this.id = id;
    }

    public Item getItem() {
        return item;
    }

    public void setItem(Item item) {
        this.item = item;
    }

    public String getName() {
        return name;
    }

    protected void setName(String newName) {
        this.name = newName;
    }

    public Map<String, AttributeValue> getValues() {
        return values;
    }

    public void setValues(Map<String, AttributeValue> values) {
        this.values = values;
    }

}

@Entity
@Table(name = "AttributeValue", uniqueConstraints = {@UniqueConstraint(columnNames = {"attribute_id", "value"})})
public class AttributeValue implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column
    private String value;

    @ManyToOne(cascade = CascadeType.ALL)
    private Attribute attribute;

    protected AttributeValue() {
        super();
    }

    public AttributeValue(String value) {
        this.value = value;
    }

    protected Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getValue() {
        return value;
    }

    /**
     * @param value the value to set
     */
    protected void setValue(String value) {
        this.value = value;
    }

    /**
     * @return the attribute
     */
    public Attribute getAttribute() {
        return attribute;
    }

    /**
     * @param attribute the attribute to set
     */
    public void setAttribute(Attribute attribute) {
        this.attribute = attribute;
    }
}

And here is the SQL of the underlying tables:

--
-- Table structure for table `Attribute`
--

CREATE TABLE `Attribute` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `item_serialNumber` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `item_serialNumber` (`item_serialNumber`,`name`),
  KEY `FK7839CA7C252F491C` (`item_serialNumber`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Table structure for table `Item`
--

CREATE TABLE `Item` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `serialNumber` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `serialNumber` (`serialNumber`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Table structure for table `AttributeValue`
--

CREATE TABLE `AttributeValue` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `value` varchar(255) DEFAULT NULL,
  `attribute_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `attribute_id` (`attribute_id`,`value`),
  KEY `FK4C1BA6C69CA0A39A` (`attribute_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Constraints for dumped tables
--

--
-- Constraints for table `Attribute`
--
ALTER TABLE `Attribute`
  ADD CONSTRAINT `FK7839CA7C252F491C` FOREIGN KEY (`item_serialNumber`) REFERENCES `Item` (`serialNumber`);

--
-- Constraints for table `AttributeValue`
--
ALTER TABLE `AttributeValue`
  ADD CONSTRAINT `FK4C1BA6C69CA0A39A` FOREIGN KEY (`attribute_id`) REFERENCES `Attribute` (`id`);
like image 528
chris Avatar asked Apr 17 '14 14:04

chris


People also ask

Which fetch type should I use in hibernate?

Hibernate can use two types of fetch when you are mapping the relationship between two entities: EAGER and LAZY. In general, the EAGER fetch type is not a good idea, because it tells JPA to always fetch the data, even when this data is not necessary. Per example, if you have a Person entity and the relationship with Address like this:

What is lazy fetchtype in hibernate?

FetchType is useful for the performance of system. If an entity is not needed to load collections, FetchType can be set to LAZY and vice- versa. We will run the example once by FetchType.LAZY and once by FetchType.EAGER. Hibernate: insert into Country (name, id) values (?, ?) Hibernate: insert into state (cid, name, id) values (?, ?, ?)

What is fetchtype eager and lazy in JavaScript?

If we set FetchType.EAGER, then collection will be loaded at the same time when the parent entity is loaded. FetchType is useful for the performance of system. If an entity is not needed to load collections, FetchType can be set to LAZY and vice- versa. We will run the example once by FetchType.LAZY and once by FetchType.EAGER.

What is the difference between fetchmode and fetchtype?

Because the orders property is a collection, we could also use FetchMode.SUBSELECT: We can only use SUBSELECT with collections. 6. FetchMode vs. FetchType In general, FetchMode defines how Hibernate will fetch the data (by select, join or subselect). FetchType, on the other hand, defines whether Hibernate will load data eagerly or lazily.


1 Answers

You have mapped the values map in Attribute using 'value' instead of 'attribute'. The @OneToMany annotation should be specified as below:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "attribute", cascade = CascadeType.ALL)
like image 119
Priyesh Avatar answered Oct 13 '22 00:10

Priyesh