1

Firstly, I am somewhat new with Hibernate. To get to know the technology I am using it in a project. I am trying to map the following database:

Campaign
  campaignId(+)
  name

Promotion
  campaignId(+)
  discount(+)
  product
  message

I've indicated the primary key in both cases with a (+). The 'campaignId' in Promotion is a foreign key to Campaign to model the 1:m mapping (A Campaign has many Promotions). Using annotations I am stuck on how to do this.

I do not really want to add a promotionId in the Promotion table as it makes working with the data cumbersome. This of course, makes the bridging table a bit tricky. I also have problems working with a foreign key that is also part of the primary key.

Is a mapping for this possible at all?


Ok, I got it working. Sort of. Have to check if persistence actually work. I did the following:

@Entity
@Table(name = "CAMPAIGNS")
@Audited
public class CampaignEntity {
    private int campaignId;
    private String name;
    private List<PromotionEntity> promotions;

    public CampaignEntity(int campaignId, String name) {
        this.campaignId = campaignId;
        this.name = name;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "cmp_id")
    public int getCampaignId() {
        return campaignId;
    }

    public void setCampaignId(int campaignId) {
        this.campaignId = campaignId;
    }

    // Campaign name here... left out to save space

    @OneToMany
    @JoinColumn(name = "cmp_id")
    public List<PromotionEntity> getPromotions() {
        return promotions;
    }

    public void setPromotions(List<PromotionEntity> promotions) {
        this.promotions = promotions;
    }
}

Promotion is a vanilla mapping (not using embedded after all), with the fields: campaignId, discount, message. (It also does not have a @ManyToOne annotation.)

Does that make sense?

Lastly, and this will be first prize: as you can see I'm using Envers to audit the whole thing. The above creates a rather ugly "CampaignEntity_PromotionEntity_AUD" table. I understand that it is needed, but how can I rename it to CAMPAIGN_PROMOTION_AUD rather?

Thanks guys!


I got an answer on a lonely website deeply hidden away in far-corners of the Hibernate's Jira error tracking website: https://hibernate.onjira.com/browse/HHH-3729.

The answer is to use @AuditJoinTable(name = "CAMPAIGN_PROMOTION_AUD") of course.

2
  • Do you mean perhaps that you don't want promotionId in the Campaign table? I'm not sure how that makes sense. Commented Mar 26, 2012 at 14:05
  • Correct, the campaign id should be in the Promotion table as a single column (cmp_id), which is also part of the Promotion's primary key. (see above.) I think I have it with the edited solution above, thanks for the help. Commented Mar 26, 2012 at 16:46

3 Answers 3

1

This is a basic example of a one-to-many relationship and its inverse.

public class Campaign
{
    @OneToMany(mappedBy = "campaign)
    private List<Promotion> promotions;
}

public class Promotion
{
    @ManyToOne
    private Campaign campaign;
}
Sign up to request clarification or add additional context in comments.

5 Comments

This does not quite work... the "Campaign campaign" entry makes it difficult to define it as part of Promotion's primary key. I need "campaign_id" to be the foreign key in this table, while also being part of Promotion's primary key. A "campaign id" together with "discount" defines the entity uniquely.
Why does it need to be part of the primary key? Just use a non-business PK (i.e. an "id" field) and define your business keys as (unique) indexes.
When a campaign is updated from the front-end, I receive a Campaign with a set of Promotions (containing discount, product and message). I now have to write a query to find all the Promotions' PKs, simply to update the Campaign. (Remember, I do not have the PK available from the collection.) That sounds awfully wrong to me.
I'm not sure I understand what you mean. Are you worried that hibernate will fetch data that you do not need?
Hi Wouter... I got it sorted. You are quite correct. Simply clearing the the set in the Campaign and populating it with the new (and modified) Promotion objects worked beautifully. As a Hibernate new-comer I am still reluctant to let Hiberante handle all of the "details". My thanks for your help.
1

You can use an EmbeddedId to create a multi-field PK.

  • Remove the PK fields from Promotion
  • Create a separate entity, say PromotionPK, without any annotations except for @Column on the PK fields
  • In Promotion, include that PK class as field, annotating it using @EmbeddedId, with getters and setters

The FK mapping is as Wouter indicated.

1 Comment

Do you mind giving a short example? I do not know how to map the @ManyToOne annotation using this composite key... where does that go? In the composite key or in the Promotion class?
0

This is what I am now using. It works well and Hibernate handles the PKs of the Promotions for me. Thanks again.

@Entity
@Table(name = "CAMPAIGNS")
@Audited
public class CampaignEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Integer campaignId;

    @Column(name = "name", nullable = false, unique = true)
    private String campaignName;

     @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
     @JoinTable(name = "CAMPAIGN_PROMOTIONS", 
                joinColumns = { @JoinColumn(name = "campaign_id") }, 
                inverseJoinColumns = { @JoinColumn(name = "promotion_id") })
     private Set<PromotionEntity> promotions;

     ...
}

and then, PromotionEntity:

@Entity
@Table(name = "PROMOTIONS")
@Audited
public class PromotionEntity implements Comparable<PromotionEntity> {

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

    @Column(name = "discount", nullable = false)
    private Integer discount;

    @Column(name = "message", nullable = false)
    private String message;

    ...
}

I also prefer annotating the fields rather than the getters as it is more compact and reads easier.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.