Suppose there is a class like that:
public class Entity {
private Long id;
private String name;
}
And table with 3 columns: id, name and address.
CREATE TABLE entity (
id NUMBER(9,0),
name VARCHAR2(255),
address VARCHAR2(1000),
Then en insert was performed:
INSERT INTO entity (id, name, address) VALUES (1, "a", "b")
Then we load and update hibernate entity:
Session session = ...
Entity entity = session.get(Entity.class, 1);
Then update name and save it again:
entity.setName("newName");
session.save(entity);
So what is address column value now - null or b? Does hibernate provide some stgrategies for such situations or I have to
add address field into entity and mark it as #Column(updatable=false, insertable = false)?
If you would put the following properties in persistence.xml(or where you have defined your hibernate properties)
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.format_sql" value="false"/>
Then you could see the queries executed by hibernate when server is run in debug mode with logged configured for debug.
If your entity is
public class Entity {
private Long id;
private String name;
private String secondName;
//Getters & Setters
}
Then executing below HQL
SELECT e FROM Entity e WHERE e.id = 121
would produce results similar to
SELECT entity0_.id AS id1_63_,
entity0_.name AS name6_63_,
entity0_.secondName AS secondName6_63_,
FROM yout_db.Entity entity0_
WHERE entity0_.id = 121
You see that here SELECT * FROM Entity was not executed instead all the fields from the Class were fetched and added to the query. So if you have ignored any field from DB then it will NOT be taking part in Queries.
For Select-Update also same thing happens.
entity.setName("newName");
session.save(entity);
Below is formatted query if you would update an entity:
UPDATE your_db.Entity
SET name = ?
secondName = ?
WHERE id = ?
This query will be executed even if only one field is changed.
Hibernate operates only with columns taken from entities, based on property name or described in annotation. So in your case 'address' value will be 'b'.
Related
I have 'iddId'(primary key) column and 'idd_id'(unused column) in the table. When I trying to execute
'findAll' method via Spring Data JPA I get empty 'iddId' field in created object because the hibernate query looks like:
select 'idd0_.idd_id as col_0_0_'...
I tried to map fields manually with a #Column(name = "iddId") annotation but nothing was changed. Then I tryed to add an additional field to the entity 'idd_id' which is annotated with #Column(name="idd_id) and received the exception:
'org.hibernate.DuplicateMappingException: Table [idd] contains physical column name [idd_id] referred to by multiple logical column names: [idd_id], [iddId]'.
Is it possible to make a query like that: 'select idd0_.iddId as col_0_0_'?
public class Idd {
#Id
#Column(name = "iddId")
private String iddId;
#Column(name = "idd_id")
private String idd_id;
}
MySql: 5.7.28
Spring Data: 2.2.2
Just add:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
to application.properties
I am using JPA's eclipseLink to perform CRUD operations on my entities. I am facing following problem:
I have two tables in DB:
CREATE TABLE User (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(30) NOT NULL UNIQUE,
email VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
signUpDate timestamp NOT NULL DEFAULT NOW()
);
CREATE TABLE Friendship (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
friendsSince timestamp NOT NULL DEFAULT NOW(),
user1_Id INTEGER NOT NULL REFERENCES User(id),
user2_Id INTEGER NOT NULL REFERENCES User(id)
);
The corresponding Entities
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
private String password;
#Temporal(value = TemporalType.DATE)
private Date signUpDate;
// constructors & setters & getters ...
}
#Entity
public class Friendship {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name="user1_Id", referencedColumnName = "id")
private User user1;
#ManyToOne
#JoinColumn(name="user2_Id", referencedColumnName = "id")
private User user2;
#Temporal(value = TemporalType.DATE)
private Date friendsSince;
// constructors & setters & getters ...
}
If I want to retrieve a list of some entities, according to "WHERE" clause of a query I get this "unknown state or association field [user1_Id] of class [com.filip.xxx.Friendship]" error.
Specifically:
I try to build this query:
Query query = mgr.createQuery("select f.id ,f.friendsSince, f.user1_Id, f.user2_Id from Friendship f where f.user1_Id = :user1Id and f.user2_Id = :user2Id or f.user1_Id = :user11Id and f.user2_Id = :user12Id");
and recieve this exception:
java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Error compiling the query [select f.id ,f.friendsSince, f.user1_Id, f.user2_Id from Friendship f where f.user1_Id = :user1Id and f.user2_Id = :user2Id or f.user1_Id = :user11Id and f.user2_Id = :user12Id], line 1, column 31: unknown state or association field [user1_Id] of class [com.filip.xxx.Friendship].
It seems like there is a problem with mapping attributes back to the entities, because I have no problem with persisting these two entities.
And interesting is that, if I run this query:
Query query = mgr.createQuery("select f from Friendship f");
It returns me the correct list of all friendships entities.
Notice that the reference variable's name in friendship entity(user1, user2) are not the same as corresponding table's variables (user1_Id, user2_Id). Before I have used the same variable names in entity as in table, but recieved this error at persisting friendship entity:
javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461):
org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'USER1_ID' in 'field list'
Error Code: 1054
Call: INSERT INTO FRIENDSHIP (FRIENDSSINCE, USER1_ID, USER2_ID) VALUES (?, ?, ?)
bind => [3 parameters bound]
Basically I don't understand, why eclipse link renames the entity's reference variables (user1 -> USER1_ID, user2 -> USER2_ID) when creating sql query, when it has than problems to map it back to the entities.
I have already tried these solutions:
Build query and return user1_Id column as user1 and user2_Id as user2
select f.id ,f.friendsSince, f.user1_Id as user1, f.user2_Id as user2 from Friendship f where f.user1_Id = :user1Id and f.user2_Id = :user2Id or f.user1_Id = :user11Id and f.user2_Id = :user12Id
but recieved the same IllegalArgumentException as above.
Could you help me solve this problem ?
Thanks
The exception
unknown state or association field [user1_Id] of class [com.filip.xxx.Friendship]
is received because you are using user1_Id name which is a database column name.
From the other hand ElementManager.createQuery() method expects JPQL string which accepts the entity's field name user1. Try to replace your query string with:
select f.id, f.friendsSince, f.user1, f.user2
from Friendship f
where f.user1 = :user1Id and
f.user2 = :user2Id or
f.user1 = :user11Id and
f.user2 = :user12Id
Using following code I can successfully retrieve address fields of a user, to do that I need to define all its fields using Projection. Imagine address has 100 fields, in this case I have to define all of them.
I am wondering if I can return just address object of customer without defining all its fields in Proposition?
I know I can retrieve id of address and use that to retrieve its object, but I am wondering if there is ano other method rather than this or defining all its fields.
Hibernate
.....
Criteria cre = session.createCriteria(User.class, "user")
.createAlias("user.address", "addr");
cre.add(Restrictions.eq("user.id", ID));
ProjectionList pl = Projections.projectionList();
pl.add(Projections.property("addr.id").as("id"));
pl.add(Projections.property("addr.unit").as("unit"));
.......
cre.setProjection(pl);
Address address = (Address) cre.list().get(0);
I used the following as well but it runs into error (could not resolve property: addr of: com.myProject.User)
pl.add(Projections.property("addr").as("address"));
Java
#Entity
public Class User {
#Id
#GeneratedValue
private long id;
#OneToOne
private Address address;
...
}
Use JPQL/HQL:
select a from User u join u.address a where u.id = :userId
The Criteria API is more limited than JPQL, and can't select any other entity than the root entity. It shouldn't be used if the query doesn't have to be dynamically composed. Of course, if the association is bidirectional, you can simply use
select a from Address a where a.user.id = :userId
or its equivalent Criteria:
Criteria c = session.createCriteria(Address.class, "a");
c.createAlias("a.user", "u");
c.add(Restrictions.eq("u.id", userId));
If the result you pull in from a query will match the fields of a DAO you have defined. I would just type-cast the result from an hql or native SQL query.
Select *
From Address a
where a.id = :userid
Address addrObject = (Address) query.uniqueResult();
Do like this
Criteria criteria = session.createCriteria(User.class, "user")
.createAlias("user.address", "addr")
.add(Restrictions.eq("user.id", userId))
.setProjection(Projections.property("addr"));
Address address = (Address) criteria.list().get(0);
Couple of options:
use lazy="false" for Address object. If you have to use lazy=true for some reason, you can run this query in a separate session and override the lazy behavior in that session.
Use the database specific query to get a list of field names and then dynamically generate Projections by looping through the field names.
For example,
In mysql
SHOW COLUMNS FROM Address
In postgres
SELECT * FROM information_schema.columns
WHERE table_schema = your_schema
AND table_name = your_table
I hope this helps.
I want Username = Administrator and Password = admin, soon after table is created (or whenever table is recreate).
Is there any way to insert first row using following code. I do not want to use a separate insert query
Is there any constraint in Hibernate to restrict user from deleting (first) row
#Entity
#Table(name = "Users")
public class Users implements Serializable {
#Id
#Column(name = "Username", unique = true, nullable = false)
private String username;
#Column(name = "Password", nullable = false)
private String password;
/**************** getter & setter ************/
}
What you seem to be looking for is called fixtures. With Hibernate you can supply import.sql file on your classpath with your initial data (insert statements).
There's a bit more information on the JBoss' site.
The import.sql file is a simple text file with SQL statements, one line per statement:
insert into users (id, username) values (1, 'administrator');
insert into users (id, username) values (2, 'user');
...
I am working on spring hibernate application and trying to delete from a table using non-id many-to-one relationship based column.
Entity classes are:
#Entity
public class Day {
#id(name = "DAY_ID")
dayId;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "DAY_ID")
List<Holiday> holidayList;
...
}
#Entity
public class Holiday {
#id(name="HOLIDAY_ID")
holidayId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "DAY_ID")
Day day;
...
}
I am trying to delete a row from holiday table using hql.
String query = "DELETE FROM Holiday WHERE day.dayId = " + dayObject.getdayId();
Query holidayDeleteQuery = getSession().createQuery(query);
holidayDeleteQuery.executeUpdate();
In the console i am getting proper delete query but on checking DB found out that the row is still there but now the DAY_ID column in holiday table is null. I am not able to figure out why is this happening?
EDIT: help!!! My main problem is why DAY_ID column is changing to null value??
I'm not sure that this is your problem, but in your query you say "DELETE FROM Holidays ...", but your Class name is Holiday. In HQL you should be using Class names rather than table names or anything else. Is this typo in your code or just on here?
Actually after looking further there are a few more problems. This is how I'd write it:
String query = "DELETE FROM Holiday h WHERE h.day = :day";
Query holidayDeleteQuery = getSession().createQuery(query);
query.setParameter("day", dayObject);
holidayDeleteQuery.executeUpdate();
To break it down - use the Class name "Holiday", assign it an alias "h" then reference the day field of the Holiday object ("h.day") and compare it to the actual Day object you have.
What is your ONDELETE foreign key constrain? Might it that other part of your application inserting a row?