spring data jpa + unwanted unique key generation - spring

I am using spring data jpa for creation of my tables. My Requirement.
I have two Tables.
Basket Table - It has one to many Relationship with the Item table. A basket can have many Items.
Item Table - Here an Item can be associated with many Baskets.
I am using IGNORE_ROW_ON_DUPKEY_INDEX to make sure that the same combination of basketId and itemId, does not get persisted
So there is a mapping table in between in which holds the mapping of baskets and items. Now, in this table, i want the combination of basketId and itemId to be unique. Below is my entity stucture.
#Entity
Class Basket{
#Id
private long basketId;
...
#OneToMany(cascade = {CascadeType.Merge, CascadeType.DETACH, CascadeType.REFRESH})
#JoinTable(
name= "mapping_table",
joinColumns = #JoinColumn(name ='basketId'),
inverseJoinColumns = #JoinColumn(name ='itemId'),
indexes = {#Index(name = "my_index", columnList = "basketId, itemId", unique = true)}
#SQLInsert(sql = "INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX (mapping_table, my_index) */ INTO mapping_table(basketId, itemId) values (?,?)")
private List<Item> itemList;
...
}
#Entity
Class Item{
#Id
private long itemId;
}
my_index with the combination of both the keys are getting created, as expected in the mapping_table
Problem 1:
In the mapping_table, for some wierd reason, a new unique constraint with only itemId is created. Due to this unique key constraint, i am not able to persist rows where an item is associated with multiple baskets. As i said, i want the combination of both the keys to be unique and i am achieving this by creating the index (my_index)
Problem 2:
Why is basketId (which is also Identifier) in the basketTable not marked as unique in the mapping table. This not a problem but more of a question. Becuase itemId which is identifier in the item table has unique key constraint in the mapping table.
Solution :
I create the tables using spring data jpa, login to the db manually and drop the unique key constraint and the persist. But this is not possible in Production
Question
I want to do alter table to drop the constraint first before the persist thing happens. How to do that.
P.S, As you can see, I have imagined these tables and have not put the names of the actual table. Not withstanding the made up table names, the problem statement is accurate. I am using Oracle as target DB

Try to use a Set instead of a List, JPA should generated the correct schema with the correct constraints.

Related

SpringBoot2 data JPA throwing ConstraintViolationException

I am using Spring Boot 2 for creating microservices. I have a scenario to save an entity. In entity for Id column I have added like below
#Id
#GeneratedValue(Strategy=GenerationType.Auto, generator="increment")
#GenericGenerator(name="increment", strategy="increment")
#Column(name="Id", insertable=false)
private Integer id;
Above works sometimes and it throws Primary Key Constraint Violation Exception sometimes. It is not consistent though. I am running it as two instances with different ports.
Error I get is unique constraint violated:
ConstraintViolationException: could not execute statement; constraint [primary_key_cons]; nested exception is ConstraintViolationException.
Only option I have is to change the strategy to sequence.
Did you insert some data manually? Maybe hibernate is generating id values which are already existing in db. If you can, just clear that table and test it again
Don't use generic generator with strategy increment. It is not recommended to use in a cluster.
increment
generates identifiers of type long, short or int that are unique only when no other process is inserting data into the same table. Do not use in a cluster.
for more info - here
Use GenerationType.SEQUENCE and crate a SequenceGenerator.
Example,
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "YourSequenceGenerator")
#SequenceGenerator(sequenceName = "YourSequence", name = "YourSequenceGenerator", allocationSize = 1)
private Integer id;

#SecondaryTable with where condition

I am creating entity for table created outside of my system. I want to bind data from other table to entity field by using #SecondaryTable (or possibly better solution), but only to do so if condition is met. IE. my table has 1 row, I want to bind data from other table (oneToMany) where certain condition is met (exactly one match from other table(transform to one to one)). Can I use #Where annotation and how? If not is there alternative?
Edit: here is the entity and additional info on the related table
#Entity
#Table(name = "RE_STORAGE_INSTANCE")
public class Movie {
#Id
#Column(name="ID_")
private Long id;
...
//Column I want to fetch
private Date dueDate;
}
Table RE_VARIABLES manyToOne to table RE_STORAGE_INSTANCE, contains fields: re_key, re_value. I want to fetch re_value only if 're_key' equals dueDate. Even though it's manyToOne, only one row of RE_VARIABLES contains due date for each RE_STORAGE_INSTANCE row.

Returned entity ID is different from the actual data saved in the database

I'm using Spring Data JPA. When I'm inspecting the Entity returned by the save(Entity) method, it is different from the actual ID saved in the database. I'm using Oracle and my Entity ID config is using sequence from Oracle db.
#Id
#Column(name = "ID", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_NAME")
#SequenceGenerator(name = "SEQ_NAME", sequenceName = "SEQ_1", allocationSize = 1)
private BigDecimal id;
Example scenario:
Insert record1 using save(record1);
Inspected record1 to have ID = 1001
Checked the db and the ID is 1002.
All other data are OK except the ID.
EDIT:
I remove all other logic in the code and leave just the saving part to isolate the issue.
I just found out that there's a db trigger that calls the SEQ1.nextVal every time a record is getting inserted. Dropping the trigger and altering the table to have DEFAULT SEQ1.nextVal solves my problem.

JPA Enitiy with one columns joined in a relationship for two other entities

Currently I'm trying to implement several entities of which one has a column in database which can represent both of other two entities.
To make it clear these are the tables I'm talking about and I can not change them
Images table:
Users table is pretty big, but part of it should be enough:
And pages table:
the logic is that image can be owned by user or by page. who it is owned by indicates by position_id and path columns. so path can be either USER or PAGE, and position_id is user's/page's id.
How can I implement ManyToOne relation between position_id and user and page in JPA?
I imageined it would look something like this:
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="position_id", insertable = false, updatable = false)
#Where(clause="path='pages'")
private Page page;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="position_id", insertable = false, updatable = false)
#Where(clause="path='users'")
private User user;
However this returns all image instances for user or page, disregarding what path it has. Furthermore, when I try to filter the value depending on Image entity's path value, it gives me LazyInitializationException.
How can one go about in solving this problem?

How to fetch the association table columns using Spring Data JPA?

I have Three tables 1) student 2) game and 3)student_game. Here studentid is the primary key of student table and gameid is the primary key of the game table. The association table has four columns 1) uuid 2) studentid 3) gameid 4) gametype.
I am using the spring data jpa, So my student entity class has relation as follows,
#OneToMany(fetch = FetchType.EAGER)
#JoinTable(name = "student_game", joinColumns = #JoinColumn(name = "studentid"), inverseJoinColumns = #JoinColumn(name = "gameid"))
private Set<Game> GameSet;
Game entity has the following relation,
#OneToMany(fetch = FetchType.EAGER)
#JoinTable(name = "student_game", joinColumns = #JoinColumn(name = "gameid"), inverseJoinColumns = #JoinColumn(name = "studentid"))
private Set<Student> studentSet;
In my business layer, I am able to fetch the set of game names for respective student by using the following logic,
Student s = studentRepository.findOne(1L);
Set<Game> games= dd.getGamesSet();
games.forEach(game-> System.out.println(game.getGameId() + " : " + game.getGameName()));
Now My question is,
I need to fetch the gameType column value from the association table (student_game) by passing input as student id.
How can I fetch the association column values?
Please suggest the best approach to fetch the association table column values.
Your mapping is wrong:
you're mapping the same, bidirectional, ManyToMany association as two different OneToMany associations, but using the same join table. This can cause undefined behavior, since you might, in the same transaction remove a game from a player, and add the player to the game.
You can't use the student_game table as a join table: every time a game is added to a player (or vice-versa), since Hibernate doesn't know anything about the uuid and gametype columns, it won't insert anything into these two columns, and this is not what you want.
What you need todo is map the student_game table as another entity. Let's call it a Play. Then, a Play has a gameType, field, one User has multiple Plays; one Game has multiple Plays. And you may of course make these two OneToMany associations bidirectional.

Resources