Spring data JPA saveAndFlush and cannot get auto increment field - java

I have object with #Id (primary key) and this is some business UIID field and I want another Long technical Id for some reasons but when saving the object I get null from getObjectId field:
#Id
private String id;
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "object_id")
private Long objectId;
public Long getObjectId() {
return objectId;
}
public void setObjectId(Long objectId) {
this.objectId = objectId;
}
I have this storage class:
interface MyObjectStorage extends JpaRepository<MyObject, String>
And this is how I save it:
final MyObject saved = storage.saveAndFlush(toSave);
saved.objectId is null here..
And in my MySQL db the objectId field is marked not null auto increment..
PS. And I don't want this objectId field to be used by JPA when findById is executed.

Hibernate/JPA isn't able to automatically create a value for your non-id-properties. The #GeneratedValue annotation is only used in conjunction with #Id to create auto-numbers.
The solution (or work-around) suggested in this forum is to create a separate entity with a generated Id, something like this:
#Entity
public class GeneralSequenceNumber {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "object_id")
private Long objectId;
}
#Entity
public class MyEntity {
#Id ..
private Long id;
#OneToOne(...)
private GeneralSequnceNumber myVal;
}

try the following code
#Id must be a type of Integer or Long
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "object_id")
private Long objectId;
private String id;
public Long getObjectId() {
return objectId;
}
public void setObjectId(Long objectId) {
this.objectId = objectId;
}
interface MyObjectStorage extends JpaRepository<MyObject, Long>

Related

I used crudrepository findAll() method on MAGICNOTIFY_CARD_INFO table but it shows other columns from another table MAGICNOTIFY_PRICE

I tried to select all columns from the table MAGICNOTIFY_CARD_INFO, so i wrote a code;
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(MagicnotifyApplication.class, args);
MagicnotifyCardInfoRepository magicnotifyCardInfoRepository =
context.getBean(MagicnotifyCardInfoRepository.class);
magicnotifyCardInfoRepository.findAll();
//SpringApplication.run(MagicnotifyApplication.class, args);
}
and this is the entity i wanted to select;
public class MagicnotifyCardInfoID implements Serializable {
#Column(name = "koname")
private String koname;
#Column(name = "name")
private String name;
#Column(name = "cardkingdom")
private String cardkingdom;
#Column(name = "cardkingdomfoil")
private String cardkingdomfoil;
#Column(name = "set")
private String set;
#Column(name = "setName")
private String setName;
#Column(name = "reldate")
private Date reldate;
#Column(name = "rarity")
private String rarity;
#Column(name = "uuid")
private String uuid;
#ManyToOne
private MagicnotifyUuidName magicnotifyUuidName;
#ManyToOne
private MagicnotifySetInfo magicnotifySetInfo;
}
public class MagicnotifyCardInfo implements Serializable {
#EmbeddedId
private MagicnotifyPriceID id;
}
public interface MagicnotifyCardInfoRepository extends JpaRepository<MagicnotifyCardInfo, Long> {
#Query(value = "SELECT * FROM MAGICNOTIFY_CARD_INFO", nativeQuery = true)
List<MagicnotifyCardInfo> findByAll();
List<MagicnotifyCardInfo> findAll();
}
but after querying, it tries to select other column item from table
MAGICNOTIFY_PRICE;
public class MagicnotifyPriceID implements Serializable {
#Column(name = "foil")
private BigDecimal foil;
#Column(name = "normal")
private BigDecimal normal;
#Column(name = "date")
private Date date;
#Column(name = "key")
private String key;
#ManyToOne
private MagicnotifyUuidName id;
}
public class MagicnotifyPrice implements Serializable {
#EmbeddedId
private MagicnotifyPriceID id;
}
I'm not sure why it happens from differently mapped two tables; how can i select from initial table MAGICNOTIFY_CARD_INFO and select from its columns?
First of all, you have not mentioned any primary key using #Id annotation inside either of your MagicnotifyCardInfoID class or MagicnotifyPriceID class
Secondly, you have given same #EmbeddedId fields "MagicnotifyPriceID id" in both the below classes
public class MagicnotifyCardInfo implements Serializable {
#EmbeddedId
private MagicnotifyPriceID id;
}
public class MagicnotifyPrice implements Serializable {
#EmbeddedId
private MagicnotifyPriceID id;
}
I don't see #Embeddable used anywhere in your program
Please refer https://www.baeldung.com/jpa-embedded-embeddable
public interface MagicnotifyCardInfoRepository extends JpaRepository<MagicnotifyCardInfo, Long> {
#Query(value = "SELECT * FROM MAGICNOTIFY_CARD_INFO", nativeQuery = true)
List<MagicnotifyCardInfo> findByAll();
List<MagicnotifyCardInfo> findAll();
}
In the above class you are passing "JpaRepository<MagicnotifyCardInfo, Long>"
Long as the data type of a primary key in your entity "MagicnotifyCardInfo"
which does not even exist.
Please fix these and try again.

Hibernate object ID

I'm trying to use objects as #Id but Hibernate doesn't seem to convert the object to the corresponding primitive type stated using an AttributeConverter.
#Entity
#Table(name = "ris_exam")
public class Exam {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long examId;
}
public class ExamId {
private Long id;
public ExamId(final Long id) {
super();
this.id = id;
}
public Long getId() {
return this.id;
}
}
#Converter(autoApply = true)
public class ExamIdCodeAttributeConverter implements AttributeConverter<ExamId, Long> {
#Override
public Long convertToDatabaseColumn(ExamId arg0) {
return arg0.getId();
}
#Override
public ExamId convertToEntityAttribute(Long arg0) {
return new ExamId(arg0);
}
}
Hibernate does this query when creating the table
create table ris_exam (id varbinary(255) identity not null, ...)
If you want to play around with wrapping of the basic column then you must take into consideration that most likely you will not be able to use the #GeneratedValue annotation on your id (the same goes for using the #EmbeddedId which is more suitable than the converter in my opinion anyway).
If you need to anyway then in my opinion you could try the #IdClass feature but remember that the ExamId class would only be used while specifiying the queries / retrieving specific entity:
#Entity
#Table(name = "ris_exam")
#IdClass(ExamId.class)
public class Exam {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long examId;
}
in DAO:
ExamId id = new ExamId(1L);
session.get(Exam.class, id);
when retrieved, the entities would contain plain long types.
Just an option for you to consider..

What is the correct way to annotate a class with a foreign id using Hibernate?

I am working on converting an existing project over to use Hibernate. I have a class like this:
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long userId;
#Column(name = "group_id_user")
private Long groupId;
#Column(name = "name")
private String name;
...
// getters and setters....
}
and a class like this:
#Entity
#Table(name = "group")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "group_id")
private Long groupId;
#Column(name="group_name")
private String groupName;
...
// getters and setters....
}
The column named "group_id_user" in the user table is supposed to be a foreign key to the column named "group_id" in the group table.
Is it okay or "correct" to have the classes structured as shown above or should they be structured as shown below to make sure that the foreign key exists in the Database?
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long userId;
#ManyToOne
#JoinColumn(name = "group_id_user")
private Group group;
#Column(name = "name")
private String name;
...
// getters and setters....
}
and
#Entity
#Table(name = "group")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "group_id")
private Long groupId;
#Column(name="group_name")
private String groupName;
...
// getters and setters....
}
I have tried using both formats but have had issues both ways. When I use the first format I have issues with the HQL syntax for joins while creating queries. When I try the second format I have issues with fetching just a User from the database without a Group, or adding a new User from a json object the has a groupId instead of a Group object. So before I spend anymore time switching back and forth between the two formats I want to know for sure which way should I be using the annotations to best fit industry standard?
I would try something like this if you could change the name of the columns too:
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY) //This means you will need the database to generate the ids, if you are using Oracle this won't work. You would need to use SEQUENCE.
private Long id;
#ManyToOne
#JoinColumn(name = "group_id") //There will be no need to specify the join column if you use group_id.
private Group group;
#Column(name = "name")
private String name;
...
// getters and setters....
}
#Entity
#Table(name = "groups")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="group_name")
private String groupName;
...
// getters and setters....
}
Also if you can I would change the name of the tables to plural.
Also I use something that helps me a lot. I have a super class called "Identifiable" which just has the id and it looks like this:
#MappedSuperclass
public class Identifiable implements Serializable {
private static final long serialVersionUID = -9027542469937539859L;
#Id
#Column(name = "ID")
#GeneratedValue
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Identifiable other = (Identifiable) obj;
if (id == null) {
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
With that you can extend all your classes with ids easily like:
#Entity
#Table(name = "users")
public class User extends Identifiable {
private static final long serialVersionUID = -90275424699375956859L;
#ManyToOne
#JoinColumn(name = "group_id") //There will be no need to specify the join column if you use group_id.
private Group group;
#Column(name = "name")
private String name;
...
// getters and setters....
}
However if you cannot change the names, let us know the issues you are having with the traces that are throwing and we might be able to help.
Thanks!

Remove redundant column for composite key in Hibernate

Hibernate creates empty "ID" column in case of code like in this post.
How tune it to not create "ID" column ("ID" is exact name of created column) or this can not be changed?
#Entity
#Table(name = "CATEGORY_RELATIONS")
public class CategoryRelations implements Serializable {
private CategoryRelationsPrimaryKey id;
#Id
#Column(name = "CATEGORY_RELATIONS_CATEGORY_ID")
private String categoryId;
#Id
#Column(name = "CATEGORY_RELATIONS_PARENT_ID")
private String parentId;
//getters and setters
#Entity
#IdClass(CategoryRelationsPrimaryKey.class)
public class CategoryRelationsPrimaryKey implements Serializable {
protected long categoryId;
protected long parentId;
//euqals, hashCode
}
}
1) #IdClass should stand at entity, not at composite id class;
2) If you already marked id properties by #Id, no separate id property is required:
#Entity
#Table(name = "CATEGORY_RELATIONS")
#IdClass(CategoryRelationsPrimaryKey.class)
public class CategoryRelations implements Serializable {
#Id
#Column(name = "CATEGORY_RELATIONS_CATEGORY_ID")
private String categoryId;
#Id
#Column(name = "CATEGORY_RELATIONS_PARENT_ID")
private String parentId;
//...
}
public class CategoryRelationsPrimaryKey implements Serializable {
protected String categoryId;
protected String parentId;
// ...
}
If you need some property named id, make it transient to avoid mapping to a DB table column.

How to add attribute to a mapping?

I'm using #MappedSuperclass annotation in the following way:
#MappedSuperclass
public abstract class Recipient {
#Id
#Column(name = "id")
private int id;
#Column(name = "email")
private String email;
//GET, SET
}
I also have two entity classe, inherited from one:
public class Player extends Recipient{
//FIELD, GET, SET
}
and
public class Partner extends Recipient{
//FIELD, GET, SET
}
The thing is private int id filed in the class Player has an additional attribute:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
Is it possible to specify that? We can override attribute with annotation #AttributeOverride, but what about to add one?

Categories

Resources