I am currently working with IntelliJ as my IDE and the project I am working on has a composite primary key for one of the database tables.
The table is named Measurements and has its fields laid out with one being MeasurementID as #EmbeddedID. Now IntelliJ shows me an error for the two fields which make up the MeasurementID, as the datasource I have linked does not have a separate table for those IDs. How do I tell IntelliJ inspections to refer to the other table for the named columns?
public class BaseMeasurement {
#EmbeddedId
private MeasurementId measurementId;
#Column(name = "power")
private int power;
...
}
#Embeddable
public class MeasurementId implements Serializable {
static final long serialVersionUID = 1L;
#Basic(optional = false)
#Column(name = "project_id")
private int projectId;
#Basic(optional = false)
#Column(name = "timestamp")
#Convert(converter = ZonedDateTimeConverter.class)
private ZonedDateTime timestamp;
...
}
Currently both "project_id" and "timestamp" are highlighted and marked as errors. I would like to solve those - meaning having the possibility to refer / link to the right table, where it can find those columns.
Related
I am using following code to define MyEntity,
#Entity
#Table(name = "MY_TABLE")
public class MyEntity {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "MY_TABLE_ID")
private Integer myTableId;
#Column(name = "MY_TABLE_NM")
private String myTableName;
//Getters Setters
}
For the first POST after my application starts, I create MyEntity everything works fine, MY_TABLE_ID starts with 1 and works as expected.
My issue is, If somebody inserts data manually before I do my POST then I get duplicate key exception as myTableId is entered as 1 which is already present.
My main problem is I can't create database sequence for using GenerationType.SEQUENCE now to resolve this as database can't be altered now.
I have tried various combinations of GenerationType, TableGenerator but I am unable to successfully tackle it.
Setting initialValue to some larger number to avoid duplicate values can temporarily resolve my problem but I am unable to do it too.
If someone can help me with initialValue with AUTO or give me some other better solution without database changes will be great :)
As MY_TABLE_ID is an identity column, following annotations will work.
#Entity
#Table(name = "MY_TABLE")
public class MyEntity {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY) // <-- IDENTITY instead of AUTO
#Column(name = "MY_TABLE_ID")
private Integer myTableId;
#Column(name = "MY_TABLE_NM")
private String myTableName;
//Getters Setters
}
The identity column will automatically assign an value as soon as the transaction is committed. You are not to set any values for an identity column, as its the job of the database to assign the values. Therefore you also don't need to think about any initial values (forget them completely for identity columns)
I tried various options in answers provided here and for similar questions on stackoverflow and other forums,
I had few limitations,
I couldn't create database sequence as my database changes were freezed.
I didn't want to introduce new Custom IdGenerator class because it would add confusion to other people working with me.
It was resolved using following change:
Adding GenericGenerator with increment strategy helped me, I made following changes to my code.
#Entity
#Table(name = "MY_TABLE")
public class MyEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator="seq")
#GenericGenerator(name = "seq", strategy="increment")
#Column(name = "MY_TABLE_ID")
private Integer myTableId;
#Column(name = "MY_TABLE_NM")
private String myTableName;
//Getters Setters
}
It helped me because,
From Hiberbate DOCs
increment
An IdentifierGenerator that returns a long, constructed by counting
from the maximum primary key value at startup. Not safe for use in a
cluster!
Since, it was incrementing already existing myTableId even if it was manually inserted, this resolved my issue.
You can also implement your own generator if you need more control.
See this interface IdentifierGenerator.
So you can get the count of records, for example through a #NamedQuery.
Then you can generate an identifier yourself.
public class MyEntityKeyGenerator implements IdentifierGenerator {
#Override
public Serializable generate(SessionImplementor session, Object object) {
// SELECT count(ent) from MyEntity ent;
Long count = (Long) session.getNamedQuery("count-query").uniqueResult();
// calc and return id value
}
}
Entity:
class MyEntity {
#Id
#GenericGenerator(name = "my_generator",
strategy = "org.common.MyEntityKeyGenerator")
#GeneratedValue(generator = "my_generator")
private Long id;...
Just do not forget about the lock.
I use the generation type Identity, which basically means that the db, takes care of Id generation.
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
#MappedSuperclass
#EntityListeners(EntityListener.class)
#EqualsAndHashCode(of = {"id", "createdAt"})
public abstract class AbstractEntity<ID extends Serializable> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private ID id;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "CREATED_AT", updatable = false)
private Date createdAt;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "UPDATED_AT")
private Date updatedAt;
}
You can also use, Sequence generation:
#Entity
#SequenceGenerator(name="seq", initialValue=1, allocationSize=100)
public class EntityWithSequenceId {
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
#Id long id;
}
I have developed a REST- API with Spring Web and Hibernate.
I deployed it in two server instances and it runs without any problem for about 5 months. Now it is mostly working but in some periods "MySQLIntegrityConstraintViolationException" with message "Duplicate entry '235648' for key 'PRIMARY'" are thrown (te duplicate id is changing in the exceptions).
The class, for which the exception is thrown, looks like this:
#Entity
#Table(name = "Metadata", catalog = "data")
public class Metadata{
private Long id;
private String field1;
private String field2;
//...
#Id
#Column(unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.TABLE)
public Long getId() {
return id;
}
//More Getters and Setters...
}
There was neither change to java code nor changes on the MySql-database.
Do you have any idea why it stopped working properly?
Most likely, the number of requests which end up creating entities which use that table for id generation has increased.
One of the remedies would be to catch that exception in a parent method and retry (probably this would be some kind of PessimisticLock exception as the id table has to be physically locked while retrieving and updating its content).
Another one would be to increase the allocationSize option, which for you is 50 being the default if no custom set-up is done. You would need to reenter the hibernate default table / columns names as this has been already created in the database:
#Id
#Column(unique = true, nullable = false)
#TableGenerator(
name="tableGen",
table="hibernate_sequences",
pkColumnName="sequence_name",
valueColumnName="next_val",
pkColumnValue="default",
allocationSize=100
#GeneratedValue(strategy = GenerationType.TABLE, generator="tableGen")
public Long getId() {
return id;
}
Here is a nice post which explains the scalability pitfalls of a TABLE generation strategy -> link
#GeneratedValue(strategy = GenerationType.IDENTITY)
worked for me.
I am currently working on a Java project with Hibernate entities (more below). In order to test my data access object layers, I am using H2 database to populate an in-memory database and throwing queries at it. Until this point, everything is fine.
However, the problem comes when simulating the #EmbeddedId annotation.
#Entity
#Table(name = "BSCOBJ")
public class BasicObject extends AbstractDomainObject {
#EmbeddedId // This annotation here
private RestrainPK restrain;
#Embeddable
public static class RestrainPK implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "CODI", nullable = false)
private String coDi;
#Column(name = "COGA", nullable = false)
private String coGa;
#Column(name = "TYOR", nullable = false)
private String tyOr;
public RestrainPK() {
}
... // Getters and setters
}
}
"Simply" creating the table BSCOBJ and populating it gives no value when fetching data (of course, I checked that the request would give result "normally"). How do I represent this nested class in a SQL table creation / value insertion request ? Is that even possible ?
Thanks in advance,
EDIT
As requested, here is some samples about the SQL / Hibernate ran.
Creation request:
CREATE TABLE BSCOBJ (CODI VARCHAR(5) NOT NULL, COGA VARCHAR(5) NOT NULL, TYOR VARCHAR(5) NOT NULL);
Insertion request:
INSERT INTO BSCOBJ (CODI, COGA, TYOR) VALUES
('HELLO', 'MAT', 'REF'),
('BONJ', 'SOME', 'DAIL'),
('SOPA', 'KDA', 'RATIO');
Request given by Hibernate when trying to run the test code:
select r.restrain.tyOr from mypackage.BasicObject r where r.restrain.coDi = :coDi and r.restrain.coGa = :coGa
With the following values:
coDi = "BONJ";
coGa = "SOME";
Throws a NoResultException. I am expecting DAIL, from the second line of the INSERT request.
I have used #EmbeddedId only one time, but I think that you need #AttributeOverrides under your #EmbeddedId
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "idpk", column = #Column(name="IDPK", nullable = false),
#AttributeOverride(name = "code", column = #Column(name="CODE")
})
and remove your #Column annotations from FormulePK
I am trying to use hibernate annotations for getting data from a MySQL database table which doesn't have a primary key defined.
However the fact is 2 columns of that table together are unique in the table. How can I achieve the same using hibernate annotation?
This is my code
#Entity
#Table(name = "coc_order_view")
public class CoCOrderDetailsTest {
#EmbeddedId
private MyJoinClassKey key;
#Column(name = "coupon_code")
private String couponCode;
some other columns and their getters and setters .....
#Embeddable
public class MyJoinClassKey implements Serializable {
private static final long serialVersionUID = -5L;
#Column(name = "product_id")
private int productId;
#Column(name = "order_id")
private int orderId;
gettes and setters....
And here is my criteria query
Criteria criteria = getHibernatetemplate().getSession().createCriteria(CoCOrderDetailsTest.class);
criteria.add(Restrictions.eq("status", "New"));
ArrayList<CoCOrderDetailsTest> orderDet = (ArrayList<CoCOrderDetailsTest>) getHibernatetemplate().get(criteria);
I am unable to get all the values from db. Kindly suggest some solutions.
After reading through your question again not sure this will help. You can't have a table without primary key(s). Read the first couple of paragraphs in this article
That said, if you can alter the table and add primary keys on those fields you need to add #IdClass annotation to your class signature for CoCOrderDetailsTest and then get rid of the #embeddable and #embeddedId notation in your classes.
Another alternative, if you can add a field to the table, would be to use an #GeneratedValue on that added primary key field and of course annotate it with #Id.
If you can't alter the table then you can't use JPA and you'll have to use JDBC.
See http://docs.oracle.com/javaee/5/api/javax/persistence/IdClass.html
A working example:
#Entity
#Table(name = "player_game_log")
#IdClass(PlayerGameLogId.class)
public class PlayerGameLog {
#Id
#Column(name = "PLAYER_ID")
private Integer playerId;
#Id
#Column(name = "GAME_ID")
private String gameId;
....
and the id class (note there are no annotations on the id class)....
public class PlayerGameLogId implements Serializable {
private static final long serialVersionUID = 1L;
private Integer playerId;
private String gameId;
Try:
String hql = "FROM CoCOrderDetailsTest WHERE status = :status";
Query query = session.createQuery(hql);
query.setParameter("status","New");
List results = query.list();
I usually use EntityManager rather than session so I'm not familiar with this syntax - and I have typically added a type to the list to be returned - like:
List<CoCOrderDetailsTest> results = query.list();
I'm trying to save a nested object using hibernate and I receive could not execute statement; SQL [n/a] Exception
CODE
#Entity
#Table(name = "listing")
#Inheritance(strategy = InheritanceType.JOINED)
public class Listing implements Serializable {
#Id
#Column(name = "listing_id")
private String listingId;
#Column(name = "property_type")
private PropertyType propertyType;
#Column(name = "category")
private Category category;
#Column(name = "price_currency")
private String priceCurrency;
#Column(name = "price_value")
private Double priceValue;
#Column(name = "map_point")
private MapPoint mapPoint;
#Column(name = "commission_fee_info")
private CommissionFeeInfo commissionFeeInfo;
}
public class MapPoint implements Serializable {
private final float latitude;
private final float longitude;
}
public class CommissionFeeInfo implements Serializable {
private String agentFeeInfo;
private CommissionFeeType commissionFeeType;
private Double value;
private Double commissionFee;
}
public enum CommissionFeeType implements Serializable { }
Using RazorSQL I saw that hibernate defines MapPoint and CommissionFee as VARBINARY
What I can't understand, is the fact that hibernate manages to save it when commissionFeeInfo is not present. It has no problem with saving MapPoint
Does anyone have an idea about what I do wrong?
UPDATE
I found out that if all attributes of CommissionFeeInfo excepting agentFeeInfoare null, the object will be saved without problems. If one of the other attributes is != null, the errors occur.
UPDATE 2
I changed the type of all attributes of CommissionFeeInfo into String and the object will be saved without problem, but I can't let the attributes as String.
I solved the problem by adding setting
#Column(name = "commission_fee_info", columnDefinition = "LONGVARBINARY")
as annotation for the field commisionFeeInfo in the class Listing
For me,
#Column(columnDefinition="text")
solves my problem.
That solution could help for a different reason. One other reason could be Column length. Check your column length. I had the same error the reason was my data exceed the size of the column.
setSignInProvider("String length > 15 ")
Before
#Column(name = "sing_in_provider", length = 15)
and then
#Column(name = "sing_in_provider", length = 100)
I was also facing the same issue . and then I solved the problem
spring.jpa.hibernate.ddl-auto=update
For me I'm using current_date for a field in my sql table. but this is a keyword in SQL so I can't use this name. I changed the field name to current_date_and_time it works for me. also I added the column name on my entity class.
#Column(name = "current_date_and_time")