Hibernate #ManyToOne mapping error - java

Good day to you. I have 2 tables.
CREATE TABLE A(
id NUMBER(10) NOT NULL,
name VARCHAR2(255) NULL,
category VARCHAR2(255) NULL,
is_hidder NUMBER(1) NULL,
is_enabled NUMBER(1) NULL,
b_id NUMBER(10) NULL,
CONSTRAINT pk_a PRIMARY KEY (ID),
CONSTRAINT fk_to_b
FOREIGN KEY (vj_users_preferences_id)
REFERENCES VJ_USER_PREFERENCES(ID)
);
CREATE TABLE B(
ID NUMBER(10) NOT NULL,
EXT_ID NUMBER(10) NOT NULL,
KEY VARCHAR2(1024) NOT NULL,
VALUE VARCHAR2(1024) NOT NULL,
CONSTRAINT PK_B PRIMARY KEY(ID)
);
For both tables I have entities and I want to map them #OneToOne.
class Entity A{
.......
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="pk_b", referencedColumnName = "id")
private B b;
}
Entity B is Audited and haven't got A field so connection is unidirectional. When I try to persist the A entity I got the error:
Caused By: org.hibernate.HibernateException: Could not determine type of dynamic map entity
This exception is being thrown from:
org.hibernate.tuple.entity.DynamicMapEntityTuplizer.BasicEntityNameResolver#resolveEntityName
Because the input is Map and it has not got: DynamicMapInstantiator.KEY in it.
Can somebody help me with this issue? I cannot figure out why Hibernate is creating that map without necessary value. Is there something wrong with my mapping?

It appeared that my UI form was receiving over 50 symbols, but database had:
EXT_ID NUMBER(10) NOT NULL
When I altered table to reflect UI possibilities (e.g. EXT_ID NUMBER(50) NOT NULL) then error was gone.
That exception, as per my understanding, is misleading in this kind of situation. I was expecting to see: SQLGrammarException of kind of it.
Hope this will help oneday.

Related

Why is a entity - value relationship implemented as a back reference in Spring Data JDBC

In Spring Data JDBC if an entity (e.g. Customer) has a value (e.g. Address) like in the example here the value has a back reference column (column customer in table address) to the entity in the db schema:
CREATE TABLE "customer" (
"id" BIGSERIAL NOT NULL,
"name" VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE "address" (
"customer" BIGINT,
"city" VARCHAR(255) NOT NULL
);
The problem with this is that if you use that Address value more than once in one entity or even in different entities you have to define an extra column for each usage. Only the primary id of the entity is stored in these columns and otherwise there is no way to distinguish from which entity it is. In my actual implementation I have five of these columns for the Address value:
"order_address" BIGINT, -- backreference for orderAddress to customer id
"service_address" BIGINT, -- backreference for serviceAddress to customer id
"delivery_address" BIGINT, -- backreference for deliveryAddress to customer id
"installation_address" BIGINT, -- backreference for installationAddress to provider_change id
"account_address" BIGINT, -- backreference for accountAddress to payment id
I understand how it works, but I don't understand the idea behind this back reference implementation. So can someone please shed some light on that issue? Thanks!
As to most good questions there are many sides to the answer.
The historical/symmetry answer
When it comes to references between entities Spring Data JDBC supports 1:1 (the one you ask about) and 1:N (lists, sets and maps).
For the latter anything but a back-reference is just weird/wrong.
And with using a back-reference for 1:1 becomes basically the same, simplifying the code, which is a good thing.
The DML process answer
With the back-reference, the process of inserting and deleting becomes much easier: Insert the aggregate root (customer in your example) first, then all the referenced entities. And it continues to work if those entities have further entities. Deletes work the other way round but are equally straight forward.
The dependency answer
Referenced entities in an aggregate can only exist as part of that aggregate. In that sense they depend on the aggregate root. Without that aggregate root there is no inner entity, while the aggregate root very often might just as well exist without the inner entity. It therefore makes sense, that the inner entity carries the reference.
The ID answer
With this design, the inner entity doesn't even need an id. It's identity is perfectly given by the identity of the aggregate root and in case of multiple one-to-one relationships to the same entity class, the back-reference column used.
Alternatives
All the reasons are more or less based on a single one-to-one relationship. I certainly agree that it looks a little weird for two such relationships to the same class and with 5 as in your example it becomes ridiculous. In such cases you might want to look in alternatives:
Use a map
Instead of modelling your Customer class like this:
class Customer {
#Id
Long id;
String name;
Address orderAddress
Address serviceAddress
Address deliveryAddress
Address installationAddress
Address accountAddress
}
Use a map like this
class Customer {
#Id
Long id;
String name;
Map<String,Address> addresses
}
Which would result in an address table like so
CREATE TABLE "address" (
"customer" BIGINT,
"customer_key" VARCHAR(20). NOT NULL,
"city" VARCHAR(255) NOT NULL
);
You may control the column names with a #MappedCollection annotation and you may add transient getter and setter for individual addresses if you want.
Make it a true value
You refer to Address as a value while I referred to it as an entity. If it should be considered a value I think you should map it as an embedded like so
class Customer {
#Id
Long id;
String name;
#Embedded(onEmpty = USE_NULL, prefix="order_")
Address orderAddress
#Embedded(onEmpty = USE_NULL, prefix="service_")
Address serviceAddress
#Embedded(onEmpty = USE_NULL, prefix="delivery_")
Address deliveryAddress
#Embedded(onEmpty = USE_NULL, prefix="installation_")
Address installationAddress
#Embedded(onEmpty = USE_NULL, prefix="account_")
Address accountAddress
}
This would make the address table superfluous since the data would be folded into the customer table:
CREATE TABLE "customer" (
"id" BIGSERIAL NOT NULL,
"name" VARCHAR(255) NOT NULL,
"order_city" VARCHAR(255) NOT NULL,
"service_city" VARCHAR(255) NOT NULL,
"deliver_city" VARCHAR(255) NOT NULL,
"installation_city" VARCHAR(255) NOT NULL,
"account_city" VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
Or is it an aggregate?
But maybe you need addresses on their own, not as part of a customer.
If that is the case an address is its own aggregate.
And references between aggregates should be modelled as ids or AggregateReference. This is described in more detail in Spring Data JDBC, References, and Aggregates

How to set the name of a class level jpa check constraint

I would like to define a constraint in JPA on an entity to make sure that either one of two properties "text" or "title" is set to a non-null value.
For this example, suppose the following Question entity class:
#Entity
#Table
public class Question {
#Id
private Long id;
#Column(nullable = true)
private String text;
#Column(nullable = true)
private String title;
}
For this class, JPA will generate the following SQL statement (we need to use the oracle dialect):
create table question (
id number(19,0) not null,
text varchar2(50 char) null,
title varchar2(10,0) null,
primary key (id)
);
In order to check that either one of the properties is set, I could add a check constraint:
#Entity
#Table
#Check(constraints = "TEXT IS NOT NULL OR TITLE IS NOT NULL")
public class Question {
...
}
Now JPA will generate this:
create table question (
id number(19,0) not null,
text varchar2(50 char) null,
title varchar2(10,0) null,
primary key (id),
check (TEXT IS NOT NULL OR TITLE IS NOT NULL)
);
On the database side, this will generate a check constraint with a random name like "SYS_C00127157".
In order to assign a meaningful name (for example: check_title) to the constraint, I could use this DDL:
create table question (
id number(19,0) not null,
text varchar2(50 char) null,
title varchar2(10,0) null,
primary key (id),
constraint check_title check(TEXT IS NOT NULL OR TITLE IS NOT NULL)
);
What I am looking for is something like this:
#Entity
#Table
#Check(name = "check_title" constraints = "TEXT IS NOT NULL OR TITLE IS NOT NULL")
public class Question {
...
}
Unfortunately, this is not possible. The #Check annotation in Java does not offer such a name property for the constraint.
Is there any other way to set a name so that the generated DDL will match the expected result?
It's not possible, unfortunately. If you take a look at how the table generation script is built:
https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/mapping/Table.java#L604
you'll see that the string, which you specify in #Check annotation is just wrapped like this:
buf.append( ", check (" )
.append( checkConstraint )
.append( ')' );
and the generation of a constraint name is given to the database.
In contrast, a few lines above, you can find that it's possible to influence the name of the unique constraints. Here you can find an example of it.
That's not possible.
In my opinion it's also not a good idea to generate the production database from JPA annotations.
The datamodel usually lives longer than the application and therefore it's good to have the DDL under control.
You should consider to use FlyWay or Liquibase for your database migrations.

Hibernate not persisting foreign keys in Mysql

I have an entity Property which has city field. Something like this:
#Entity
class Property {
...
#ManyToOne(fetch = FetchType.LAZY)
private City city;
...
}
So each property (e.g house or apartment) belongs to only one city.
Now here is a thing, if I try to log generated SQL by Hibernate, it is generating the foreign key in a right way:
Hibernate:
alter table property
add constraint FKdn1hnohufcwdr4a401xabcjn
foreign key (city_id_city)
references city (id_city)
However, if I check my Mysql database, there is no foreign key there, only index is generated:
show create table property;
leads to:
| property | CREATE TABLE `property` (
`id_property` int(11) NOT NULL AUTO_INCREMENT,
`created_at` datetime NOT NULL,
`deal_type` varchar(15) NOT NULL,
`publisher_type` varchar(15) NOT NULL,
`type` varchar(15) NOT NULL,
`updated_at` datetime NOT NULL,
`city_id_city` int(11) DEFAULT NULL,
PRIMARY KEY (`id_property`),
KEY `FKdn1hnohufcwdr4a401xabcjn` (`city_id_city`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
So the question is why there is no CONSTRAINT FOREIGN KEY () REFERENCES definition in my database?
The problem ended up to be the database engine after I switched to InnoDB engine it started working, as MyISAM does not implement foreign keys.
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
The annotation #ManyToOne is used to map two tables that have a relationship instance by a foreign key, it could not automatically create a foreign key in your database
You need to define the list Property in the City Entity and add the relationship there as well

Replace row when duplicate primarykey found

I have a table where I wish to replace a row when duplicate Primary (unique) key is found.
Create table History (
id varchar(5) not null,
name varcah(30),
primary key (id)
) engine=InnoDB character set utf8;
I'm using this with hibernate. id column is declared as #Id #Column(name="id", unique=true, nullable=false)
Help me change the above SQL, Hibernate annotations to allow REPLACE on duplicate primary key is found
The database Primary Key is not meant to be ever updated/replaced. There are workarounds but those are bad-practices.
You'd better use AUTO INCREMENT(MySQL), IDENTITY(MSSQL) or SEQUENCE(ORACLE, PostgreSQL) ID generation.
If you use MANUAL ID assignment and you get duplicate primary key violations, you have to check your current application concurrency design. Is the manual id assignment not thread-safe?
A database sequence or an AUTO-INCREMENT ID will save you from getting duplicate primary key violations.

Entity class with a composite primary key doesn't have getter and setter

I have an entity class userdetails which has the username, userid (numeric) and password fields, with username and userid forming a composite primary key. This is negotiable, and possibly unimportant to the main problem.
I have another class, connectiontable, which has userid as the primary key. The sql code used to generate the relevant tables is as follows:
create table usertable
(
userid int NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
username varchar(128) NOT NULL UNIQUE,
password varchar(128) NOT NULL,
CONSTRAINT USER_PK PRIMARY KEY(username, userid)
);
That's the sql code for usertable. The following is for connectiontable
create table connectiontable
(
userid int not null,
username varchar(128) not null,
connections varchar(32670) not null,
CONSTRAINT CONNECTION_PK PRIMARY KEY(username, userid),
CONSTRAINT CONNECTION_FK FOREIGN KEY(username,userid) REFERENCES usertable(username,userid)
);
There are a bunch of other things in connectiontable, but those are irrelevant. I use netbeans 7.2.1 and Jave EE6. I use the 'create entities from database entries' but for some reason, I don't have a getter and setter for either userid or username. They are in connectiontablePK, but I can't seem to make use of that. For example, when I generate the jsf pages, I want to be able to do something like:
Connectiontable con = new Connectiontable();
con.getUsername();
But it complains because it can't find that method in connectiontable.java.
Can anyone advise me why this is the case, and how I can solve it? Thank you.
... You're not posting the Java code, which I suspect would help but:
Anytime in JPA when you have a composite primary key, you have to have an 'embedded' primary-key class. I suspect you have a class definition similar to the following:
#Embeddable
public class UserNameId {
private int userid;
private String username;
}
And then usertable and connectiontable both contain the following (or similar):
#Embedded
#Id
private UserNameId userNameId;
... So you should expect a getter/setter for userNameId, but not the embedded fields, like you expect.

Categories