Oracle column name issue - java

I have parent-child mapping in hibernate where the entities are connected through table.
The problem is that column automatically created by hibernate in this table is called like "_actions_id". But I use Oracle and it says that column name "_actions_id" is invalid.
It works fine when I wrap the name with "" and execute the script manually, but is there a way to make hibernate to wrap all columns with "" ?

In your example, you specified a join table, which is for scenarios like this
People table:
PID | Name
1 | Albert
2 | Bob
TelephoneNumbers table:
TID | Tel
1 | 123-456
2 | 456-789
3 | 789-012
Join table:
PID | TID
1 | 1
1 | 2
2 | 3
I.e. the column that connects the current entity to the entity in the collection is in neither the current table nor the table for the collection entity. This is more useful for the many-to-many mapping, but you can also use it for OneToMany if you don't have control over the TelephoneNumbers table for example. Otherwise you should just use plain #JoinColumn.
The usage of #JoinTable has been explained many times by many websites. See the JavaDoc and this question.

I think you want a custom NamingStrategy. I got the idea here. In your case, it would be something like:
public class MyNamingStrategy extends DefaultNamingStrategy {
public String logicalCollectionColumnName(String columnName, String propertyName, String referencedColumn) {
return "`" + super.logicalCollectionColumnName(columnName, propertyName, referencedColumn + "`";
}
}

Related

How to format data in column for WHERE clause just before executing SELECT?

I am using Microsoft SQL Server with already stored data.
In one of my tables I can find data like:
+--------+------------+
| id | value |
+--------+------------+
| 1 | 12-34 |
| 2 | 5678 |
| 3 | 1-23-4 |
+--------+------------+
I realized that the VALUE column was not properly formatted when inserted.
What I am trying to achieve is to get id by given value:
SELECT d.id FROM data d WHERE d.value = '1234';
Is there any way to format data in column just before SELECT clause?
Should I create new view and modify column in that view or maybe use complicated REGEX to get only digits (with LIKE comparator)?
P.S. I manage database in Jakarta EE project using Hibernate.
P.S.2. I am not able to modify stored data.
One method is to use replace() before the comparison:
WHERE REPLACE(d.value, '-', '') = '1234'

Spring Data with strict In-clause

See updated question below
I want to query for elements where every element is required to have all given attributes of e.g. a set to be returned, not only one.
Default Spring Data Jpa Query, where one attribute is enough:
findAllByAttributeIn(Set<Attribute> setAttr)
Example problem
For these elements (abstracted, no actual table)
id | attr
----------
1 | A
2 | A,B
3 | A,B,C
with this filter:
setAttr: [A,B]
the default query
findAllByAttributeIn(Set<Attribute> setAttr)
returns all elements (by ids):
[1,2,3]
Desired result is only the second element (with [A,B]).
Is that possible with the given Spring Data Jpa query keywords or is the only solution to create a custom query?
Updated question:
There are two entities, Media and Tag. They have a many-to-many relationship which is realised in the table Media_has_tags. Every media can have any number of tags (0..*). So in my Spring app, media has a set of tags as an attribute and vice versa. The classes:
Media = {
id: string,
Set<Tag> tags,
...
}
Tag = {
id: string,
Set<Media> medias,
...
}
The corresponding tables are:
Media
-------
id | ...
Tag
-------
id | ...
title | ...
Media_has_tags
-------
media_id | tag_id
And now I have a set of tags with which I want to get all medias which have every tag of that set. They can have more tags of course, but they need to have every tag of the set I am providing.
Concrete example:
Media
-------
id | ...
-------
1 |
2 |
Tag
-------
id | title | ...
1 | A |
2 | B |
Media_has_tags
-------
media_id | tag_id
1 | 1
2 | 1
2 | 2
Given a set of tags [A, B] I want only media with id 2 as a result since media with id 1 doesn't have tag 'B'.
Can I achieve that with Keywords and if, how or do I have to build my own query?
Sorry, but your question is incorrect initially.
findAllByAttributeIn(Set<Attribute> setAttr)
produces an SQL request like this:
select * from <table_name> t where t.attribute in (?,?,?...?)
So according to RDBMS-rules your result is correct and expectable.
What is a real structure for your abstract tables?
id | attr
----------
1 | A
2 | A,B
3 | A,B,C
In real life it would be somethink like this:
id | attr
----------
1 | A
2 | A
2 | B
3 | A
3 | B
3 | C
And again - in this case the result you have got is ok for any RDBMS.
Give us real examples from your project, please
Update because of question update:
OK, the problem has been clarified.
In this case there is no straight way to solve it using standard CrudRepository syntax. But you can try to write #Query request to manage to get the goal.
In a clear SQL this problem has to be solved by using group by together with having. It would be something like this:
select media_id
From media_has_tags
Where tag_id in(1,2 3)
Group by media_id
Having count(*)=3
In terms of SpringData it means that you have to create MediaHasTagsRepository interface and an appropriate query method to get looked ids. After that you can easily find medias you're looking for.
But this approach is not looking good IMHO. The best way I suppose is to find all the medias by the your initial query and than filter them by the given condition in Java.
E.g. you have a List<Media> where each element has an least a one tag that you are looking for. Then we can do a loop to find medias that contains all the looked tags:
List<Media> list; // here is a filled list of medias
Set<String> titles; // here is a set of title interseptions we a looking for
final List<Media> result = new ArrayList<>();
for (Media media: list) {
if (!list.getTags().isEmpty()){
Set<String> tagTitles = list.getTags().stream().map(item -> item.getTitle()).filter(title -> titles.contains(title)).distinct().collect(Collectors.toSet());
if (tagTitles.size() == titles.size()) {
result.add(media);
}
}
}

Replace subString in string with Hibernate select query

I have a table i would like to query with hibernate (java)
for exmaple this table has 2 column
full_name | age
---------------------
Mr Dony | 30
Mrs Clark | 32
Doc Who | 43
i would like to replace each value of Doc to Doctor show criteria result will look:
full_name | age
---------------------
Mr Dony | 30
Mrs Clark | 32
Doctor Who| 43
I don't want to edit the acctual table data
i just want to use somthing like replace-subString how could i achieve it using hibernate?
if that's matter my db's are PostgreSQL and vertica
Hibernate's Dialect is exactly for this job. What you can do is:
Implement a subclass of org.hibernate.dialect.PostgreSQL81Dialect or any of its descendants depending on actual PostgreSQL version.
Register a custom function (see PostgreSQL81Dialect's constructor) like below.
Declare your dialect with Hibernate
Then use it as you would with native query update table_name set full_name = replace(full_name, 'Doc', 'Doctor'). Note that this would replace all 'Doc' occurrences with 'Doctor'.
public class PostgreSQL81DialectEx extends PostgreSQL81Dialect {
public PostgreSQL81DialectEx() {
registerFunction( "replace", new SQLFunctionTemplate(StandardBasicTypes.STRING, "replace(?1, ?2, ?3)") );
}
}

Hibernate auto generate second id

Suppose that I have a table with only two columns ID and Car, and the Car column can have repeated values, for example:
id | car
1 | 200
2 | 200
3 | 201
4 | 201
5 | 201
6 | 202
I need a new column which automatically generates a second id grouped by Cars when new records are inserted, something that looks like this:
id | car | second_id
1 | 200 | 1
2 | 200 | 2
3 | 201 | 1
4 | 201 | 2
5 | 201 | 3
6 | 202 | 1
I've tried something like this but does not work:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name = "car")
private int car;
#GeneratedValue(generator="second_id")
#GenericGenerator(name="second_id", strategy="com.example.SecondIdGenerator")
#Column(name = "second_id", unique = false, nullable = false, length = 20)
private int secondId;
SecondIdGenerator class for now only returns a fixed value for test, but this value is not showing in the db, in other words, it is not working.
How i do this?
Hibernate has something for this?
(I'm using MySQL db)
I am unaware of any tool support for this sort of column.
You can implement calculation of the value for the second_id column with a trigger. You would probably want a "before insert" trigger. The trigger would find the existing maximum second_id for the car that is being inserted and add one for the new row's second_id value. If you allow updates to the car column, you could support recalculation of the second_id column in the same way (although this would leave holes in the second_id sequence for the prior car value's second_id column).
You might find it easier to create a stored procedure that encapsulates the business logic if you are going to have multiple triggers that maintain the column value.
You would also want to have a unique constraint on (car, second_id). If you don't do this, you will get duplicates whenever you have multiple clients insert rows with the same car value. The unique constraint will only allow the first to commit to finish successfully. All other concurrent transactions that tried to insert a row with the same car value (and computed the same second_id value) will fail. Obviously, you need to handle this exception in the client by cleaning up and retrying the transaction.
at run time if there is no #Id specified hibernate will get an exception , i think you can change the structure of your table.

Get TEXT column value in psql

I have created simple entity with Hibernate with #Lob String field. Everything works fine in Java, however I am not able to check the values directly in DB with psql or pgAdmin.
Here is the definition from DB:
=> \d+ user_feedback
Table "public.user_feedback"
Column | Type | Modifiers | Storage | Stats target | Description
--------+--------+-----------+----------+--------------+-------------
id | bigint | not null | plain | |
body | text | | extended | |
Indexes:
"user_feedback_pkey" PRIMARY KEY, btree (id)
Has OIDs: no
And here is that I get from select:
=> select * from user_feedback;
id | body
----+-------
34 | 16512
35 | 16513
36 | 16514
(3 rows)
The actual "body" content is for all rows "normal" text, definitely not these numbers.
How to retrieve actual value of body column from psql?
This will store the content of LOB 16512 in file out.txt :
\lo_export 16512 out.txt
Although using #Lob is usually not recommended here (database backup issues ...). See store-strings-of-arbitrary-length-in-postgresql for alternatives.
Hibernate is storing the values as out-of-line objects in the pg_largeobject table, and storing the Object ID for the pg_largeobject entry in your table. See PostgreSQL manual - large objects.
It sounds like you expected inline byte array (bytea) storage instead. If so, you may want to map a byte[] field without a #Lob annotation, rather than a #Lob String. Note that this change will not be backward compatible - you'll have to export your data from the database then drop the table and re-create it with Hibernate's new definition.
The selection of how to map your data is made by Hibernate, not PostgreSQL.
See related:
proper hibernate annotation for byte[]
How to store image into postgres database using hibernate

Categories