hibernate generator won't insert with uniqueidentifier

RMorrisey picture RMorrisey · Jun 20, 2010 · Viewed 7.5k times · Source

I'm trying to map an entity using Hibernate Annotations, so that when a record is created and saved (via cascade), an ID is automatically generated. With my current setup (or a few others I've tried) I get the following error:

    ...org.hibernate.exception.ConstraintViolationException: 
could not insert: [com.gorkwobbler.shadowrun.karma.domain.AttributeScore]
    ...java.sql.SQLException: 
Caused by: java.sql.SQLException: Cannot insert the value NULL into column 'id', table 'KARMA_DEV.dbo.Character'; column does not allow nulls. INSERT fails.

I can see the following insert statement being issued:

Hibernate: insert into character (version, alias, firstName, lastName) values (?, ?, ?, ?)

Clearly this is wrong, there is no "id" parameter.

My table schema, for now, is simply:

Character(
 id uniqueidentifier, --primary key
 alias varchar(max),
 firstName varchar(max),
 lastName varchar(max),
 version int --for hibernate
)

I am using SQL Server 2008 R2, Express edition.

My annotations are split between a mapped superclass, DomainEntity, and a concrete class, KarmaCharacter:

@MappedSuperclass
public abstract class DomainEntity implements Serializable /* Needed for HOM retainUnsaved */ {
    private static final long serialVersionUID = 1L;
    private String id;
    private Integer version;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Generated(value=GenerationTime.INSERT)
    //@GeneratedValue(generator="hibernate-uuid.hex")
    //@GenericGenerator(name="hibernate-uuid.hex", strategy="org.hibernate.id.UUIDHexGenerator", parameters=@Parameter(name="separator", value="-"))
    @AccessType(value="field")
    public String getId() {
        return id;
    }

    @Version
    @AccessType(value="field")
    public Integer getVersion() {
        return version;
    }
}

@SuppressWarnings("serial")
@Entity
@Table(name="character")
public class KarmaCharacter extends DomainEntity {
    private String alias;
    private String lastName;
    private String firstName;

    private SortedSet<AttributeScore> attributeScores;

    public KarmaCharacter() {
        //default constructor
    }

    @Column
    @AccessType(value="field")
    public String getAlias() {
        return alias;
    }

    @Column
    @AccessType(value="field")
    public String getFirstName() {
        return firstName;
    }

    @Column
    @AccessType(value="field")
    public String getLastName() {
        return lastName;
    }

//...omitted some transient code and a collection property for brevity

    public void setAlias(String alias) {
        this.alias = alias;
    } 

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

If someone could tell me the right way to generate uniqueidentifer-type ID's with hibernate in SQL Server, and get them to be saved properly, it would be much appreciated.

Answer

Pascal Thivent picture Pascal Thivent · Jun 20, 2010

I can see the following insert statement being issued (...). Clearly this is wrong, there is no "id" parameter.

Indeed, when using the uniqueidentifier SQL Server type, Hibernate has to use newid(). But your current annotations are not telling it to do so. I think you need the guid generator here:

@Id
@GenericGenerator(name = "generator", strategy = "guid", parameters = {})
@GeneratedValue(generator = "generator")
public String getId() {
    return id;
}

Some additional remarks:

  • The GUID column type is really meant to hold a GUID generated by Microsoft's algorithm, you can't use Hibernate's UUID algorithm.
  • You don't need the Generated annotation on an Id, just remove it.
  • I also wonder why you are "messing" wit AccessType, I would just remove them.
  • I would actually not use a GUID (see this article) but this is another story.