For simplicity I'll chop the tables down quite a bit
Given the tables REPORT_DOWNLOAD, REPORT
REPORT has ID, NAME
REPORT_DOWNLOAD has ID, FK_REPORT_ID
I essentially want to build the query:
SELECT R.NAME, RD.ID FROM REPORT_DOWNLOAD RD, REPORT R WHERE
RD.FK_REPORT_ID = R.ID
My entity for REPORT_DOWNLOAD essentially looks like
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "FK_REPORT_ID", referencedColumnName = "ID", nullable = false)
private ReportOrm report;
But that queries the whole REPORT table. Is there a way to reference just the NAME column from the entity?
#SomeAnnotationThatMagicallyPulls("FK_REPORT_ID", "NAME")
private String reportName;
I feel like there must be some Hibernate / JPA magic here that I could use
Related
Something very bizarre have been happening. I have a very simple Entity recipe like so
#Data
#Entity
#Table(name = "recipe", schema = "public")
#AllArgsConstructor
#NoArgsConstructor
public class Recipe {
#Id
#GeneratedValue(
strategy = GenerationType.IDENTITY
)
#Column(name = "id", updatable = false, nullable = false)
private long id;
#Column(name = "name")
private String name;
#Column(name = "instructions")
private String instructions;
#Column(name = "date_added", nullable = false)
private String dateAdded;
#Column(name = "last_edited", nullable = false)
private String lastEdited;
}
and I have this post service that should post the 4 string attribute to the database
public void postRecipe(Recipe recipe){
var sql = """
INSERT INTO public.recipe ("name","instructions","date_added","last_edited")
VALUES (?, ?, ?, ?)
""";
jdbcTemplate.update(
sql,
recipe.getName(),
recipe.getInstructions(),
recipe.getDateAdded(),
recipe.getLastEdited()
);
}
However when the following jason is sent using postman, I get the null value error.
{
"name":"test",
"instructions":"don't eat",
"date_added":"03/04/2017",
"last_edited":"03/04/2017"
}
ERROR: null value in column \"date_added\" of relation \"recipe\" violates not-null constraint\n Detail: Failing row contains (3, null, don't eat, null, test)
The strangest thing is that only the "name" and "instruction" columns receive their data and not the other columns. I have tried adding another String attribute to the Entity class and it also cannot get data from the jason.
Edit 1:
I have tried adding the data directly through pgadmin and it worked fine
INSERT INTO recipe (name, instructions, date_added, last_edited)
VALUES ('test', 'test instruction', '2020/03/05', '2020/05/08');
It looks like your deserialization is broken - transforming your JSON into the Java entity, which results in some null values present. Most likely because date_added != dateAdded (field name), and Jackson cannot properly set a value.
I recommend having a look at Jackson guide: https://www.baeldung.com/jackson-annotations, #JsonProperty specifically. And overall do not mix entities and DTOs
After many trials and errors I was able to come up with a solution but still have no clue as to why this is happening. It turns out the under score in the annotation is the problem.
//won't work
#Column(name = date_added)
//works
#Column(name = dateadded)
This is pretty strange because I am fairly certain that the under score is generated by hibernate.
if anyone know why this is happening please let me know... for now I will just stay away from the under scrolls.
I have an issue join fetching in case of OneToOne relation in the same class. Example follows:
class Data {
...
#Id
#Column(name = "DATA_ID")
Long id;
#Column(name = "DATA_OWNER_ID")
#ForeignKey(entityClass = Owner.class)
Long ownerId;
#Column(name = "DATA_RELATED_ID")
#ForeignKey(entityClass = Data.class)
Long relatedDataId;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "DATA_RELATED_ID", referencedColumnName = "DATA_ID", insertable = false, updatable = false)
Data relatedData;
}
I want to select data based on some conditions, while also fetching/initialising the "relatedData", all in one JPQL query:
SELECT owner.something1, data
FROM Data data
JOIN Owner owner on data.ownerId = owner.id
JOIN FETCH data.relatedData
WHERE data.something2 = :expectedSomething2
Executing that JPQL query throws an exception:
Query: ReadObjectQuery(name="relatedData" referenceClass=Data)|Exception:
javax.persistence.PersistenceException: Exception [EclipseLink-6044] (Eclipse Persistence Services - 2.6.2.v20151217-774c696): org.eclipse.persistence.exceptions.QueryException
Exception Description: The primary key read from the row [DatabaseRecord(
DATA_X => something
DATA_Y => something2
...
)] during the execution of the query was detected to be null. Primary keys must not contain null.
Which is somewhat true, as there is no DATA_ID column listed. Changing JOIN FETCH to LEFT JOIN FETCH returns both owner.something1 and data, but the relatedData object is null (relatedDataId is not null).
I can see, that the id for relatedData is returned from DB, but eclipselink trims it in valueFromRowInternalWithJoin and trimRowForJoin methods.
The Id column name attribute value is the reason of this exception. Same issue found in eclipselink version 2.3.2 but it works fine in version 2.0.0
Try with this entry :
eclipselink.jpa.uppercase-column-names=true
OR Try with upper and lower case one by one which on will work for you.
#Id
#Column(name = "UUID") // UUID - uppercase/lowercase one by one
Long id;
I've somehow resolved this issue, but haven't had the time to correctly identify the cause. Final (working) version differences are:
I could've forgotten to add get/set for relatedData
I have specified targetEntity = Data.class in #OneToOne
Fetch is now a LEFT JOIN FETCH and appears before JOIN Owner owner
I have a user entity identified by two natural ids, something like
#Entity
#Table(name = "user", uniqueConstraints =
{ #UniqueConstraint(columnNames = "email"),
#UniqueConstraint(columnNames = "nick") })
public User()
{}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private id;
#Column(name = "email", unique = true, nullable = false, length = 31)
#NaturalId(mutable = true)
private String email;
#Column(name = "nick", unique = true, nullable = false, length = 31)
#NaturalId(mutable = false)
private String nick;
However, when I try to execute
session.byNaturalId(User.class).with(LockOptions.READ).using("email", "admin#mail.com").load();
it throws an exception
org.hibernate.HibernateException: Entity [pervasive.com.gmail.tigerjack89.forum.shared.model.entities.User] defines its natural-id with 2 properties but only 1 were specified
at org.hibernate.event.spi.ResolveNaturalIdEvent.<init>(ResolveNaturalIdEvent.java:75)
at org.hibernate.event.spi.ResolveNaturalIdEvent.<init>(ResolveNaturalIdEvent.java:52)
at org.hibernate.internal.SessionImpl$BaseNaturalIdLoadAccessImpl.resolveNaturalId(SessionImpl.java:2607)
at org.hibernate.internal.SessionImpl$NaturalIdLoadAccessImpl.load(SessionImpl.java:2722)
at pervasive.com.gmail.tigerjack89.forum.server.model.orm.StorageManager.getByNaturalId(StorageManager.java:217)
at pervasive.com.gmail.tigerjack89.test.local.MyHibernateTest.test1(MyHibernateTest.java:37)
at pervasive.com.gmail.tigerjack89.test.local.MyHibernateTest.main(MyHibernateTest.java:23)
Why is this? I think it's also due to the log of the SQL syntax generated by Hibernate. Indeed, it is strange (redundant) at this point and I think it's the cause of the exception
Hibernate:
alter table user
add constraint UK_t8tbwelrnviudxdaggwr1kd9b unique (email, nick)
Hibernate:
alter table user
add constraint UK_ob8kqyqqgmefl0aco34akdtpe unique (email)
Hibernate:
alter table user
add constraint UK_pvnbxcfihb58o5n2n1fnc7fh1 unique (nick)
EDIT: Reading the code again, I thought that the problem could be related to the #UniqueConstraints annotations. However, even if I try to remove one of them, Hibernate continues to genetate the above SQL syntax.
I would make the email address alone the NaturalId and then your query would work.
When two columns are identified as the NaturalId it creates a Composite Key.
Nick could still be used as a foreign Key.
You've a composite naturalId key (email,nick) so you can have multiples results with simple email arg.
you've to use
session
.byNaturalId(User.class)
.with(LockOptions.READ)
.using("email", "admin#mail.com")
.using("nick", "admin")
.load();
You can also use Metamodel
session
.byNaturalId(User.class)
.with(LockOptions.READ)
.using(User_.email.getName(), "admin#mail.com")
.using(User_.nick.getName(), "admin")
.load();
I want to make a JPQL query with a collection of non entities. This is my Table entity :
#Entity
#Table(name = "ct_table")
public class Table {
...
#CollectionOfElements(fetch = FetchType.EAGER)
#JoinTable(name = "ct_table_result", joinColumns = #JoinColumn(name = "tableId"))
#MapKey(columns = { #Column(name = "label") })
#Column(name = "value")
private Map<String, String> tableResults;
...
then I try to make a query like this
select count(*) from table where table.tableResults['somekey'].value='somevalue'
but I get the following exception:
Cannot create element join for a collection of non-entities!
Any suggestion??
thanks for your time
EDIT:
I use JPA 1 and hibernate 3.3. Default libraries in JBoss 5
The JPA 2 spec (page 139) defines the KEY() and VALUE() functions to access the key and the value of a map-valued element collection:
select count(t.id) from Table t
where KEY(t.tableResults) = 'somekey' and VALUE(t.tableResults) = 'somevalue'
Suppose I have the following entity which models a subscriber and uses a CollectionTable to model a list of subscriptions like so:
#Entity
#Table(name = "SUBSCRIBER")
public class Subscriber {
#ElementCollection
#CollectionTable(name = "PERSON_ORG_SUBSCRIPTIONS",
joinColumns = { #JoinColumn( name = "PERSON_ID", referencedColumnName = "PERSON_ID" ),
#JoinColumn( name = "ORG_ID", referencedColumnName = "ORG_ID" ) } )
#Column(name = "SUBSCRIPTION_NAME")
protected Set<String> _subscriptionNames;
}
So this creates a table with columns for PERSON_ID, ORG_ID and SUBSCRIPTION_NAME.
I'm trying to create a database index on the SUBSCRIPTION_NAME column. But if I put the following annotation on _subscriptionNames:
#org.hibernate.annotations.Index( name="subscription_idx", columnNames={"SUBSCRIPTION_NAMES"} )
I get an exception:
org.hibernate.MappingException: Unable to find logical column name from physical name null in table SUBSCRIBER
I also tried using the org.hibernate.annotations.Table annotation on the Subscriber entity, but there does not seem to be a way to have it reference the PERSON_ORG_SUBSCRIPTIONS table.
I'm using Hibernate 3.5.3 and PostgreSQL 9.0.
Is the column with name "SUBSCRIPTION_NAME" present in the table SUBSCRIBER?
Are you planning to create index on table from the code? You should propably use hibernate.hbm2ddl.auto=create