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.
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.
Related
I'm currently trying to create a many to many mapping using eclipselink. Please note that for this specific example no table to resolve the relation is used (I kwon that this is not a good practice but it is necassary for this specific example).
I've created a database schema and the tables employee3 and insurance to map. The employee table holds a column called insurance_id which is part of the primary key in order to create the mapping. Same goes for insurance with employee_id.
Now for the code:
Here is the code for the two classes:
First off Employee:
#Entity
#Table(name="employee3", schema = "many_to_many")
public class EmployeeManyToMany
{
protected EmployeeManyToMany()
{
}
#Id
private int id;
private String firstName;
private String lastName;
#ManyToMany(cascade = CascadeType.PERSIST)
private Collection<InsuranceManyToMany> insurance;
public EmployeeManyToMany(int id, String firstName, String lastName)
{
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
insurance = new ArrayList<InsuranceManyToMany>();
}
.....
And Insurance:
#Entity
#Table(name = "insurance", schema = "many_to_many")
public class InsuranceManyToMany
{
#Id
#Column(name = "id")
private int insuranceId;
private String company;
#ManyToMany(mappedBy = "insurance", cascade = CascadeType.PERSIST)
private Collection<EmployeeManyToMany> employee;
protected InsuranceManyToMany()
{
}
public void addEmployee(EmployeeManyToMany emp)
{
employee.add(emp);
}
public InsuranceManyToMany(String company, int insuranceId)
{
this.insuranceId = insuranceId;
this.company = company;
employee = new ArrayList<EmployeeManyToMany>();
}
....
After I create an Employee object and add a list of insurances to it i try to persist it into the database.
Which results in the following error:
javax.persistence.RollbackException: Exception [EclipseLink-4002]
Eclipse Persistence Services - 2.7.3.v20180807-4be1041):
org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: null value
in column "insurance_id" violates not-null constraint
Detail: Failing row contains (1, hans, test, null).
Error Code: 0
Call: INSERT INTO many_to_many.employee3 (ID, FIRSTNAME, LASTNAME) VALUES
(?, ?, ?)
bind => [3 parameters bound]
Query: InsertObjectQuery(swd_ws18_06_Tag3.EmployeeManyToMany#88d98e)
I have no idea why this occures since the values are never null.
Any help is appreciated!
BR
Simon
I' currently trying to build a complete Spring Boot Rest service with jdbc connection by myself.
At the moment I'm struggling with a minor problem of comprehension regarding hibernate and storing entities.
I have one base class:
#Entity
#Table
public abstract class Person {
private int id;
private String firstName;
private String middleName;
private String lastName;
#Id
#GeneratedValue(generator = "increment")
#GenericGenerator(name = "increment", strategy = "increment")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Column
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
#Column
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
And 2 sub classes:
#Entity
#Table
public class Member extends Person{
private String memberNumber;
#Column
public String getMemberNumber() {
return memberNumber;
}
public void setMemberNumber(String memberNumber) {
this.memberNumber = memberNumber;
}
}
and
#Entity
#Table
public class Supporter extends Person {
private String supporterNumber;
#Column
public String getSupporterNumber() {
return supporterNumber;
}
public void setSupporterNumber(String supporterNumber) {
this.supporterNumber = supporterNumber;
}
}
The base class is abstract because I want to prevent to create a instance of this without specify a person either a member or supporter. But in the database scheme I still want to have 3 tables because of normalization.
Which annotations should I use now the reach this target? How can I link a row of member or supporter to the member now? I'm really confused.
Thanks!
The mapping from class to table is done by hibernate. Since a relational database table and a Java object are kinda different ORM mappers have different strategies how to map between them.
Hibernate can use the following strategies:
MappedSuperclass
Single Table (default)
Joined Table
Table per class
You can read more about them from the official documentation.
They have different pros and cons and normally it is safest to just use the default. However the default strategy only uses one table so you need to switch to an other strategy.
The Table per class will create three tables. You can also check the examples for MappedSuperclass and Joined Table which will also use multiple tables.
From the official documentation:
#Entity(name = "Account")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public static class Account {
#Id
private Long id;
private String owner;
private BigDecimal balance;
private BigDecimal interestRate;
//Getters and setters are omitted for brevity
}
#Entity(name = "DebitAccount")
public static class DebitAccount extends Account {
private BigDecimal overdraftFee;
//Getters and setters are omitted for brevity
}
#Entity(name = "CreditAccount")
public static class CreditAccount extends Account {
private BigDecimal creditLimit;
//Getters and setters are omitted for brevity
}
Will create these tables:
CREATE TABLE Account (
id BIGINT NOT NULL ,
balance NUMERIC(19, 2) ,
interestRate NUMERIC(19, 2) ,
owner VARCHAR(255) ,
PRIMARY KEY ( id )
)
CREATE TABLE CreditAccount (
id BIGINT NOT NULL ,
balance NUMERIC(19, 2) ,
interestRate NUMERIC(19, 2) ,
owner VARCHAR(255) ,
creditLimit NUMERIC(19, 2) ,
PRIMARY KEY ( id )
)
CREATE TABLE DebitAccount (
id BIGINT NOT NULL ,
balance NUMERIC(19, 2) ,
interestRate NUMERIC(19, 2) ,
owner VARCHAR(255) ,
overdraftFee NUMERIC(19, 2) ,
PRIMARY KEY ( id )
)
I am using spring-data-jpa on a spring webmvc project. I am facing an issue using query creation on a Repository of one of my Entities. Below you can see my Entity, my Repository and the Exception.
My Entity:
#Entity
#Table(schema = "mainschema")
#XmlRootElement
public class Municipalperson implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(nullable = false)
private Integer id;
#Basic(optional = false)
#Column(name = "municipal_id", nullable = false)
private Integer municipal_id;
#Basic(optional = false)
#Column(nullable = false, length = 60)
private String firstname;
public Municipalperson(Integer id, Integer municipal_id, String firstname) {
this.id = id;
this.municipal_id = municipal_id;
this.firstname = firstname;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getMunicipal_id() {
return municipal_id;
}
public void setMunicipal_id(Integer municipal_id) {
this.municipal_id = municipal_id;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
}
my Repository:
#Repository
public interface MunicipalpersonRepository extends JpaRepository<Municipalperson, Integer> {
List<Municipalperson> findByMunicipal_idOrderByLastnameDesc(int municipal_id);
}
and the exception,
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'municipalpersonRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property municipal found for type Municipalperson!
I tried to set municipal_id as int, then as Integer and the same for the parameter municipal_id on my Repository, but none worked. Also, I renamed the Repository to findByMunicipalidOrderByLastnameDesc and findByMunicipalIdOrderByLastnameDesc but it didn't work either.
Finally I renamed the municipal_id to municipalId (underscore removed) and also renamed getters/setters and the Repository (findByMunicipalIdOrderByLastnameDesc) and the issue was resolved.
My question is why this is happening?
I solved this error by renaming field to the name without underscore.
#Column(name = "municipal_id", nullable = false)
private Integer municipalId; // <-- field was renamed
The underscore _ is a reserved character in Spring Data query derivation (see the reference docs for details) to potentially allow manual property path description. So there are two options you have:
Stick to the Java naming conventions of using camel-case for member variable names and everything will work as expected.
Escape the _ by using an additional underscore, i.e. rename your query method to findByMunicipal__idOrderByLastnameDesc(…).
I'd recommend the former as you're not going to alienate fellow Java developers :).
Please add the following properties to application.properties file:
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
I know the question was answered a long time ago, but it can help others in the future.
According to the Docs, underscore is a special character used by spring to separate properties names. If you really want to stick with snake case notation, you can set nativeQuery to true and solve this problem:
#Query(value = "SELECT * FROM municipalperson WHERE municipal_id=?1 ORDER BY last_name DESC", nativeQuery = true)
List<Municipalperson> findByMunicipal_idOrderByLastnameDesc(int municipal_id);
One other approach that worked for me is to use #JsonProperty to differentiate between field name used in REST request/response and that used for database.
For example:
#JsonProperty("municipalId")
private Integer municipal_id;
I'm brand new to Hibernate, and I'm trying to get a fairly simple Hibernate code snippet to work. After reading the tutorials, I'm totally choking on the full implementation.
For one, when it comes to the hbm2ddl.auto property, I'm setting it to validate because I just don't like the idea of Hibernate creating my table structure (I'm old fashioned; perhaps that will change as I become more comfortable with Hibernate though). In any event, here's the table I just created on a MySQL server:
CREATE TABLE users (
id INT NOT NULL AUTO INCREMENT,
email VARCHAR(200) NOT NULL,
title VARCHAR(25),
first_name VARCHAR(100),
middle_name VARCHAR(100),
last_name VARCHAR(100),
suffix VARCHAR(100),
PRIMARY KEY (id)
);
Thise corresponds to the following POJOs/entities in my app's code:
#Entity
#Table(schema="my_db", name="users")
public class User {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private Integer id;
#Column(name="email")
private String email;
// ???
private PersonName personName;
public User(final String email, final PersonName personName) {
super();
setEmail(email);
setPersonName(personName);
}
// Getters and setters omitted for brevity...
}
public abstract class BaseName {
public abstract String toName();
#Override
public String toString() {
return toName();
}
}
public class PersonName extends BaseName {
private String title;
private String firstName;
private String middleName;
private String lastName;
private String suffix;
public PersonName(final String title, final String firstName, final String middleName, final String lastName, final String suffix) {
super();
setTitle(title);
setFirstName(firstName);
setMiddleName(middleName);
setLastName(lastName);
setSuffix(suffix);
}
// Getters and setters omitted for brevity...
}
What annotations/config do I need to add so that User#personName gets persisted as an embedded PersonName object inside the users table? In other words, User is an entity and contains a PersonName as an embedded objects (non-entity).
Also, any other obvious annotations I'm missing? Thanks in advance!
As suggested by user #Snow Blind, Embedded objects are what you want.
Let's start with class PersonName:
#Embeddable
public class PersonName extends BaseName {
#Column(name = "title")
private String title;
#Column(name = "first_name")
private String firstName;
#Column(name = "middle_name")
private String middleName;
#Column(name = "last_name")
private String lastName;
#Column(name = "suffix")
private String suffix;
// ...
}
Now add the #Embedded tag here:
// ...
#Embedded
private PersonName personName;
// ...
Hope this helps!
You can check the title 2.2.2.4. Embedded objects (aka components) in docs:
http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#entity-mapping-property
The following query throws the exception:
Query query = session.createQuery("from Associate as a order by a.username asc");
associates = query.list();
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [ca.mypkg.model.Associate#0]
If I create an entry in the database with id of 0 it works just fine. I don't really get it because I'm just trying to load all the entries in the db not just a specific one.
Similar questions I've found have been concerned with trying to load an object with a given ID I'm doing no such thing.
Associate class:
#Table(name = "user")
#XmlRootElement(name = "associate")
public class Associate implements Serializable {
private String username;
private String password;
private String firstName;
private String lastName;
private String userType;
private int id;
private String email;
private String isActive;
private Department dept;
private String lastUpdated;
private String associate_type;
// ...
#Id
#GeneratedValue
public int getId() {
return id;
}
#OneToOne
#JoinColumn(name = "dept")
public Department getDept() {
return dept;
}
From my experience this type of error message usually means it does not find joined entity by mentioned id, and not the entity requested in the query (Associate, in your case).
My guess is that Associate class contains a join entity which has primitive type primary key.