-->
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.  [ 4 posts ] 
Author Message
 Post subject: NaturalId with nullable column?
PostPosted: Tue Jan 06, 2009 10:27 pm 
Newbie

Joined: Tue Jan 06, 2009 9:38 pm
Posts: 3
Hibernate version: 3.2.6
Database: HSQLDB 1.8 (for easy TDD - prod will be MySQL)

I have a situation where I need to store a row where one of the null columns is required for the natural ID. The best example I can think of is something like:
Code:
CREATE TABLE Messages (
  messageId BIGINT NOT NULL PRIMARY KEY,
  header VARCHAR NOT NULL,
  body VARCHAR NOT NULL,
  footer VARCHAR,
  CONSTRAINT Messages_Unique UNIQUE (header, body, footer));


Basically, I should be able to differentiate between:
("foo", "bar", null)
("foo", "bar", "baz")
("foo", "lorem", null)
("foo", "bar", "loremipsum")
etc.

I tried mapping this with Hibernate using @NaturalId, but this doesn't work since Messages.footer is nullable. Does anyone have any suggestions for how I can update my object model to handle this?

Here's a simple test case demonstrating the problem:
Code:
import org.hibernate.annotations.NaturalId;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.ejb.HibernatePersistence;
import org.hsqldb.jdbcDriver;

import junit.framework.TestCase;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

import java.util.Properties;

public class UniqueNullTest extends TestCase {
 
  EntityManagerFactory emf;
 
  protected void setUp() {
    emf = createEntityManagerFactory();
  }
 
  protected void tearDown() {
    emf.close();
  }
 
  public void testMessage() throws Exception {
    EntityManager em = emf.createEntityManager();
    em.getTransaction().begin();
    em.merge(new Message("hello", "world", null));
    em.getTransaction().commit();
    em.close();
   
    em = emf.createEntityManager();
    em.getTransaction().begin();
    try {
      em.merge(new Message("hello", "world", null));
      fail("Should not be able to insert a duplicate");
    } catch (EntityExistsException expected) {
    }
   
    em = emf.createEntityManager();
    em.getTransaction().begin();
    em.merge(new Message("hello", "world", "goodbye!"));
    em.getTransaction().commit();
    em.close();
   
    em = emf.createEntityManager();
    em.getTransaction().begin();
    try {
      em.merge(new Message("hello", "world", "goodbye!"));
      fail("Should not be able to insert a duplicate");
    } catch (EntityExistsException expected) {
    }
  }
 
  @Entity
  public static class Message {
   
    @Id
    @GeneratedValue
    private Long id;
   
    @NaturalId
    @Column(nullable = false, updatable = false)
    private String header;

    @NaturalId
    @Column(nullable = false, updatable = false)
    private String body;

    @NaturalId
    @Column(nullable = true, updatable = false)
    private String footer;

    public Message() {
    }

    public Message(String header, String body, String footer) {
      this.header = header;
      this.body = body;
      this.footer = footer;
    }
   
    public Long getId() {
      return id;
    }
   
    public void setId(Long id) {
      this.id = id;
    }
   
    public String getHeader() {
      return header;
    }
   
    public void setHeader(String header) {
      this.header = header;
    }
   
    public String getBody() {
      return body;
    }
   
    public void setBody(String body) {
      this.body = body;
    }
   
    public String getFooter() {
      return footer;
    }
   
    public void setFooter(String footer) {
      thi.footer = footer;
    }
  }
 
  private static EntityManagerFactory createEntityManagerFactory() {
    Ejb3Configuration config = new Ejb3Configuration()
    .addAnnotatedClass(Message.class);
    Properties prop = config.getProperties();
    prop.setProperty(Environment.DRIVER, jdbcDriver.class.getName());
    prop.setProperty(Environment.DIALECT, HSQLDialect.class.getName());
    prop.put(HibernatePersistence.AUTODETECTION, "class");
    prop.put(Environment.URL, "jdbc:hsqldb:mem:.;shutdown=true");
    prop.put(Environment.USER,  "sa");
    prop.put(Environment.PASS, "");
    prop.put(Environment.HBM2DDL_AUTO, "update");
    return config.buildEntityManagerFactory();
  }
}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 06, 2009 11:59 pm 
Regular
Regular

Joined: Wed Oct 15, 2008 6:59 am
Posts: 103
Location: Chennai
use insertable=false ...

_________________
If u feel it will help you, don't forget to rate me....


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 07, 2009 2:39 am 
Newbie

Joined: Tue Jan 06, 2009 9:38 pm
Posts: 3
Madan_Prabhu wrote:
use insertable=false ...


All that does is prevent me from specifying the footer on insert:

Output when running with insertable = true (from original post):
Code:
Hibernate:
    insert
    into
        UniqueNullTest$Message
        (id, body, footer, header)
    values
        (null, ?, ?, ?)
Hibernate:
    call identity()
Hibernate:
    insert
    into
        UniqueNullTest$Message
        (id, body, footer, header)
    values
        (null, ?, ?, ?)
Hibernate:
    call identity()


There was 1 failure:
1) testMessage(UniqueNullTest)junit.framework.AssertionFailedError: Should not be able to insert a duplicate
        at UniqueNullTest.testMessage(UniqueNullTest.java:51)


And when insertable = false:
Code:
Hibernate:
    insert
    into
        UniqueNullTest$Message
        (id, body, header)
    values
        (null, ?, ?)
Hibernate:
    call identity()
Hibernate:
    insert
    into
        UniqueNullTest$Message
        (id, body, header)
    values
        (null, ?, ?)
Hibernate:
    call identity()


There was 1 failure:
1) testMessage(UniqueNullTest)junit.framework.AssertionFailedError: Should not be able to insert a duplicate
        at UniqueNullTest.testMessage(UniqueNullTest.java:51)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 07, 2009 2:47 am 
Newbie

Joined: Tue Jan 06, 2009 9:38 pm
Posts: 3
Nevermind, I just got what you were getting at...


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

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.