-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: Defining one-to-many relationships with cascade save
PostPosted: Mon Apr 07, 2014 1:46 pm 
Newbie

Joined: Fri Jun 24, 2011 11:21 am
Posts: 2
I am having some trouble describing a one-to-many relationship with JPA. The problem that I am facing is that I think I should be able to save the one side of the relationship and have the many side receive the newly create id for the one side.

Here is a general schema of the problem domain:

Code:
Item ::= {
   *id,
   name
}

ItemCost ::= {
    *itemId,
    *startDate,
    cost
}
* indicates PK

In the above schema an item will have a cost for some given amount of time. It will only have one cost for that time period thus this is a one-to-many relationship.

This is where I get into trouble. Here is how go about describing the relationship with POJOs and JPA and am getting myself stuck.
Code:
@Entity
@Table(name = "Item", schema = "dbo")
public class Item implements Serializable {

    private Integer id;
    private String name;
    private Set<ItemCost> costs = new HashSet<>(0);

    public Item() {

    }

    public Item(String name) {
        this.name = name;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id")
    public Integer getId() {
        return id;
    }

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

    @Column(name = "Name")
    public String getName() {
        return name;
    }

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

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "id.itemId")
    public Set<ItemCost> getCosts() {
        return costs;
    }

    public void setCosts(Set<ItemCost> costs) {
        this.costs = costs;
    }

    public void addCost(Date date, int amount) {
        getCosts().add(new ItemCost(date, amount));
    }
}

In the Item class I have described the fields that represent the schema plus an additional field for the relationship. Since the relationship is one-to-many I have added that annotation and instructed it to cascade all as I want it save, update, delete etc its children when it is changed. Additionally, I have added the mappedBy attribute to the annotation to indicate that I want to relationship bound by the id->itemId fields in the ItemCost (I think this is where my assumption is wrong: I am assuming this instructs the JPA provider, in this case Hibernate, that upon save I want the item id to be placed into the ItmmCost at this location before propagating the save).
Code:
@Entity
@Table(name = "ItemCost", schema = "dbo")
public class ItemCost implements Serializable {

    private Id id;
    private int cost;

    public ItemCost() {
        id = new Id();
    }

    public ItemCost(Date startDate, int cost) {
        id = new Id();
        id.setStartDate(startDate);
        this.cost = cost;
    }

    @Column(name = "cost")
    public int getCost() {
        return cost;
    }

    public void setCost(int cost) {
        this.cost = cost;
    }

    @EmbeddedId
    public Id getId() {
        return id;
    }

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

    @Embeddable
    public static class Id implements Serializable {

        private int itemId;
        private Date startDate;

        public Id() {

        }

        public Id(Date startDate) {
            this.startDate = startDate;
        }

        @Column(name = "itemId")
        public int getItemId() {
            return itemId;
        }

        public void setItemId(int itemId) {
            this.itemId = itemId;
        }

        @Column(name = "startDate")
        public Date getStartDate() {
            return startDate;
        }

        public void setStartDate(Date startDate) {
            this.startDate = startDate;
        }

        @Override
        public int hashCode() {
            int hash = 3;
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            final Id other = (Id) obj;
            if (this.itemId != other.itemId)
                return false;
            if (!Objects.equals(this.startDate, other.startDate))
                return false;
            return true;
        }
    }
}

I have additionally filled out the Item save with its field cost and additionally with its primary key of itemId and startDate. This is an embedded id as that seems to best describe the scenario with a compound id. Additionally, I may need to pass around this identifier in the future.

Code:
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

Item item = new Item("A Jar");
item.addCost(new Date(), 10);

em.persist(item);
em.getTransaction().commit();

em = emf.createEntityManager();
item = em.find(Item.class, item.getId());
Assert.assertNotNull(item);
assertThat(item.getCosts().size(), is(1)); // fails here with a result of 0

The test is rather strait forward and fails on the very last line. If I look at the db I am getting an entry in the ItemCost table but it has an itemId of zero (the default value of int in java).

Since, the cascade is saving I figure that my assumption about the mappedBy is inccorect. Is there some piece of meta data that is missing that will help inform the JPA provider that it should apply the Item.Id value to the children defined in the mapping?

SO: http://stackoverflow.com/questions/22919153/how-to-describe-one-to-many-relationship-jpa-hibernate


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.