Hibernate ManytoOne mapping deleting child when parent does not exists - java

I have one java class Specification which is getting deployed to Specs master table.
#Entity
#Table(name = "SPECS_MASTER")
Specification
{
#Id
#Column(name = "SPEC_ID")
String specId;
//other attribute
}
Another Class
#Entity
#Table(name = "PRODUCT_SPECS")
public class SpecificationValue {
#Id
#Column(name = "NODE_SPECS_ID")
private Integer specId;
#ManyToOne()
#JoinColumn(name = "SPEC_ID")
private Specification specification;
//other mappings and attribute
}
My problem here is when I am deleting a specification_value by hibernate, if Specs master does not exists than hibernate is not able to delete specification value entry, which is expected in this mapping.
I want to be able to delete specification values even if specs_master does not exits, is there any way I can do this?

Related

Override Foreign Key and Unique constraint creation in Hibernate Spring Boot

I have below Hibernate relations in a spring boot application.
#Entity
#Table(name = "projects")
public class Project {
#Embedded
private ProjectParameters parameters;
}
#Embeddable
public class ProjectParameters {
#Column(name = "hvacConfigs")
#ElementCollection(targetClass = HVACUserConfigModel.class)
#CollectionTable(uniqueConstraints = #UniqueConstraint(columnNames = {}), foreignKey = ForeignKey(name = "project_hvacConfig_fk"))
private Set<HVACUserConfigModel> hvacConfigs;
}
#Entity
#Table(name = "hvacuserconfig")
public class HVACUserConfigModel {
#Id
#GeneratedValue
private Integer id;
}
Mysql table auto-generated is as follows. Please open images in these below links as I don't have 10 reputation to post images on stackoverflow.
The issue is I am able to save multiple projects with same project like below
Project_uid | hvacConfigs_id
------------------------------
1001 | 1
1001 | 2
Adding (1002 | 1) throws unique constraint violation.
I am able to get it working by changing table definition explicitly using mysql workbench by removing the unique constrain UK_me0ekntab0gknshag0xjjv35x. To remove unique constrain I have to first remove foreign key constrain FKeygabcnr2stdchxqpb5wuinf2 which is being referred by unique constrain. After these changes, I from spring boot app, I insert new rows it is successfully added with values (1002 | 1) & (1002 | 2).
I am able to explore that #CollectionTable annotation, annotated in hvacConfigs field in Java code, provides ways to insert uniqueConstraint and foreignKey definition as part of attribute definition. I have tried tweaking these attributes of annotation but with no success.
Please let me know if you have any solution how to override the unique constraint and foreign key constraints using java code so that this works without any manual adjustment to mysql table explictly.
To be honest, this is unclear what you want to achieve. But your mapping is invalid. You can use #ElementCollection annotation only with basic or embeddable types. If you want operate with HVACUserConfigModel as with an entity you should use #OneToMany association.
So, you can correct your mapping in this way:
#Embeddable
public class ProjectParameters {
#ElementCollection
#CollectionTable(
name = "hvacuserconfig",
joinColumns = #JoinColumn(name = "hvacConfigs_id")
)
private Set<HVACUserConfigModel> hvacConfigs;
}
#Embeddable
public class HVACUserConfigModel {
// #Id annotation is not used with #Embeddable types
// Like basic types, embeddable types do not have any identity,
// being managed by their owning entity.
private Integer id;
// ...
}
or in this way:
#Embeddable
public class ProjectParameters {
#OneToMany
#JoinColumn(name = "hvacConfigs_id")
private Set<HVACUserConfigModel> hvacConfigs;
}
#Entity
#Table(name = "hvacuserconfig")
public class HVACUserConfigModel {
#Id
#GeneratedValue
private Integer id;
}
We solved this using ManytoMany annotation instead of ElementCollection annotation. It works the same way creating new intermediate table to contain Project Id and HVACUserConfigModel id but does not create the unique index.

Hibernate/JPA persist OneToMany objects with generated UUID's

I have been using Hibernate a lot but using Hibernate/JPA with UUID got me stumped a bit. I am using hibernate 5.2.12.Final.
I have an object called TimePeriod with this mapping:
#Entity(name = "time_period")
public class TimePeriod extends AbstractDomainObject {
#OneToMany(mappedBy = "timePeriod", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<TimePeriodBlock> timePeriodBlocks = new ArrayList<>();
...
public void addTimePeriodBlock(TimePeriodBlock timePeriodBlock) {
timePeriodBlock.setTimePeriod(this);
this.timePeriodBlocks.add(timePeriodBlock);
}
...
With the following child relationship:
#Entity(name = "time_period_block")
public class TimePeriodBlock extends AbstractDomainObject {
...
#ManyToOne
#JoinColumn(name = "time_period_id", nullable = false)
private TimePeriod timePeriod;
...
They share this super class:
#MappedSuperclass
public abstract class AbstractDomainObject {
...
#Id
#GeneratedValue
#Column(name = "id", columnDefinition = "uuid", updatable = false)
private UUID id;
...
When I execute the following:
// pseudo code
TimePeriod t = new TimePeriod();
t.setName("test");
TimePeriodBlock b = new TimePeriodBlock();
t.addTimePeriodBlock(b);
em.persist(t);
I get the exception:
...
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value : test.TimePeriodBlock.timePeriod
...
Some notes:
I strongly believe that this could be because Hibernate generates the UUID (and not the database) but, since I am not sure, I hope some fellow Developer might know how this could work.
I am using PostgreSQL 9.6 and the database can also generates UUIDv4 but requires compiling an extra extension so I opted for Hibernate to generate it.
When I enter some data in the database and retrieve the data it is fetched without any error.
Storing other objects without #ManyToOne relationships do store without any error and have a UUID that is generated by Hibernate.
Well after some debugging and using Luay Abdulreheem suggestion I found out that hibernate is working just fine; in this case my objects are send using a REST interface (using Jackson) and the reference to the parent was lost as the unmarshalling of the JSON is done using fields.
So nothing to see here, move along...

Spring and JPA 2.0 - Single value Primary Key through OneToOne

I have a simple table (ActivityLog) and I want it to have a PK that is also a FK to another table (User).
It seems to be a common thing to have, and I tried to follow this wikibook
Primary Keys through OneToOne and ManyToOne Relationships. The example there involved a composite key. I need just a primitive key, so I ended up with:
#Entity
public class User {
#Id
private Long id;
// other stuff
}
#Entity
public class ActivityLog {
#Id
#OneToOne(optional = false)
#JoinColumn(name="user_id", referencedColumnName="id")
private User user;
// other stuff
}
Unfortunately i am getting:
Caused by: java.lang.IllegalArgumentException: This class [class com.example.ActivityLog] does not define an IdClass
at org.hibernate.metamodel.internal.AbstractIdentifiableType.getIdClassAttributes(AbstractIdentifiableType.java:183)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation$IdMetadata.<init>(JpaMetamodelEntityInformation.java:253)
I tried to annotate ActivityLog with:
#IdClass(Long.class)
(even though from what I understand it is applicable only for composite keys), yet I am getting the exact same error.
Is my case different than what's on the mentioned wikibook?
Is Spring at fault here? (As suggested in this question? (no accepted answers)).
This should help:
#Entity
public class ActivityLog {
#Id
#Column(name = "user_id")
private Long id;
#OneToOne(optional = false)
#JoinColumn(name="user_id", referencedColumnName="id")
private User user;
// other stuff
}
Btw. I would expect, that you need more logs per user, so you would probably need some additional (generated) id anyway ...

Hibernate Unidirectional OneToMany Not Working with composite id

I've been bashing my head on my keyboard for two days trying to figure this out...
Some background: We have a data model set up with a Perl code base that runs straight native SQL statements to the database via ODBC. For certain reasons, we decided to rewrite the code in Java... I thought it would be a good idea to use Hibernate to define all of the mappings. We don't want to edit the data model.
For simplicity sake, I can express the problem with only part of our data model. We have the entities "Job","JobDatabase" and "JobTable".
Job has a PK of job_name. Database has a PK of job_name,name. Table has a PK of job_name,src_database_name,name. As you may expect, Job has a OneToMany relationship with JobDatabase, and Database has a OneToMany with JobTable.
For purposes of this test, I'm starting with empty tables and trying to create some sample data. I can insert a Job and a JobDatabase, but when I try to insert the JobTable, Hibernate throws an error. Or more accurately, that is where it complains. It doesn't start executing my code because it detects the mapping error. However, if I remove the association between JobDatabase and JobTable, it will insert all Job and JobDatabase records correctly with no errors.
Sample Classes (all fields have getters/setters... there are also many other fields):
#Entity
#Table(name="Job")
public class Job implements Serializable {
#Id
#Column(name="job_name",nullable = false)
private String jobName;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "job_name", referencedColumnName = "job_name")
private Set<JobDatabase> databases;
}
#Entity
#Table(name="JobDatabase")
public class JobDatabase implements Serializable {
#Id
#Column(name="job_name",nullable = false)
private String jobName;
#Id
#Column(name="name",nullable = false)
private String name;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "job_name", referencedColumnName = "job_name"),
#JoinColumn(name = "name", referencedColumnName = "src_database_name")
})
private Set<JobTable> tables;
}
#Entity
#Table(name="JobTable")
public class JobTable implements Serializable{
#Id
#Column(name="job_name",nullable = false)
private String jobName;
#Id
#Column(name="src_database_name",nullable = false)
private String srcDatabaseName;
#Id
#Column(name="name",nullable = false)
private String name;
}
The error:
Exception in thread "main" org.hibernate.MappingException: Unable to find column with logical name: src_database_name in JobDatabase
I keep getting this error. I do not understand why it is looking for the referenced column in the entity "owning" the mapping. src_database_name does indeed only exist in JobTable - it is referred to as "name" in JobDatabase. JobTable also has a "name" field, but it refers to the name of the Table.
You need to have src_database_name column in your JobDatabase table. Or you can change src_database_name to other column name.
For composite key reference column must be present in your source table.

Hibernate disable default behaviour

I have a problem with my Hibernate making assumptions on what to call columns.
Specifically, when I do a #ManyToOne field, where I refer to a column in the other Table.
What happens is that, If I do not enter a #JoinColumn annotation as well, it maps the field with an underscore in it's name.
For example, i have this class:
#Entity
public class User extends AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "userFK")
private List<TwitterAccount> twitterAccounts;
/* GETTERS & SETTERS OMITTED */
}
And then I have the TwitterAccount class:
#Entity
public class TwitterAccount extends AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(fetch = FetchType.LAZY)
private User userFK;
}
What happens is that when it tries to get the Twitter accounts for a certain user, I get the exception: MySQLSyntaxErrorException: Unknown column 'twitteracc1_.userFK_id' in 'field list'
Look at what it tries to map the userFK to: userFK_id. Of course it doesn't exist! I haven't given it that name.
So the question comes down to: Is it possible to turn off this functionality? (The functionality that turns the column name into 'field_'foreignkey')
I am aware that using #JoinColumn(name = "userFK") would solve it, but I'd rather turn it off instead.
Regards
This is the default as specified by the JPA specification
The concatenation
of the following: the name
of the referencing relationship
property or field of the referencing
entity or embeddable class;
""; the name of the referenced
primary key column. If there is no
such referencing relationship
property or field in the entity, or if
the join is for an element collection,
the join column name is
formed as the concatenation of the
following: the name of the entity;
""; the name of the referenced
primary key column.
In hibernate this is implemented in a NamingStrategy in this case the EJB3NamingStrategy. You can implement your own version of this deciding whatever you want to use. But that will probably only complicate/confuse people (which might expect the standards to apply).

Categories