I'm using Ebean, and define such a model:
#Entity
#Table(name = "users")
public class User extends Model {
#Id
public String id;
public String email;
public String name;
}
You can see the field id is String, and has a #Id annotation.
Now I save it:
User user = new User();
user.id = "abc";
user.email = "a#a.com";
Ebean.save(user);
But when I saved it, I found the value of it's id is: 1, not abc I specified.
I checked the sql, found the table generate:
create table users (
id varchar(255) not null,
email varchar(255),
name varchar(255),
constraint pk_users primary key (id))
;
create sequence users_seq;
You can see there is a seq users_seq which has been used when inserting a user.
How to define the model or how to configure Ebean to let it not do anything to the #Id field? Just let it use my specified value?
===========
UPDATE
Sorry, guys, I found this strange behavior is because of my mistake!
Yes, I use it with playframework 1, and I tried to create a play-ebean module for myself. But there is something wrong: When I save a model, I cleared the id value by mistake!
So the assigned value abc is missing, then Ebean will try to use a seq to get a new value for it.
Thanks for all you help, and sorry again, I will be more careful when I ask question next time.
Isn't it better idea to create another unique field and use it optionally ie. String userCode or something?
Play with Ebean uses auto incrementation of Id's to make sure the Id is unique so I'd personally didn't change that as all docs assumes that id of model is some numeric kind.
You can thought use Play's routes to find user by its string-id and still use Long id to perform basic operations.
(I'm writing in Play's context as I assume that you ask in it ;) )
You need to extend GenericModel instead of Model if you want to operate on your own #Id field. I am also talking in PlayFramework context.
Related
I am developed Rest API with sprint boot, jpa, hibernate and PostgreSQL. My goal is to be able to generate auto-incremented id for using with code and using database tool such as D Beaver without writing any extra queries for getting next ID value and etc.
I have created entity User. I tried generating id in two ways:
GenerationType.IDENTITY
When using GenerationType.IDENTITY it successfully creates table with name user, sequence with name user_id_seq and adds a default value for user.id column nextval('user_id_seq'::regclass). Everything in database is as expected and it works great with database tool, but problem occurs when I am trying to insert new row from my API. When trying to insert new row hibernate executes query
select currval('user_id_seq')
to get id value and I am getting error
org.postgresql.util.PSQLException: ERROR: invalid name syntax
because of those quotes around user. It should execute
select currval('user_id_seq')
I believe that the problem here is because I use table name user which is a reserved keyword, but I want to keep it this way because this naming matches other tables pattern.
GenerationType.SEQUENCE
If I use annotations:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_generator")
#SequenceGenerator(name="user_generator", sequenceName = "user_id_seq", allocationSize=1)
it creates table 'user', sequence 'user_id_seq' but doesn't add user.id column default value, so I can't insert new rows using database tool without specifying id value. But using this generation type my API works fine.
It is also worth mentioning that I am using spring.jpa.hibernate.ddl-auto=create-drop and manually dropping and recreating schema each time so there wouldn't be any unnecessary sequences/tables left.
#Entity
#Table(name = "`user`")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// other properties...
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
// other getters and setters...
}
So... It is possible to somehow connect those two ways and create one working solution? I need to have default value for column and that hibernate would also know how to generate that id.
P.S. I don't want to change table/entity naming or execute SQL to correct tables when running application. I believe that there should be a better approach.
After a lot of hours of debugging I ended up extending PostgreSQL82Dialect and overriding getIdentitySelectString function to remove quotes from table name.
I want to create an entity containing 2 fields that need to be unique in together. One of the fields is a Boolean:
#Entity
public class SoldToCountry {
private String countryId;
private Boolean isInt;
}
For a given String there should never exist more than 2 entries one with isInt:true and the other isInt:false.
I read the doc about #Id but it seems that Boolean is not supported. For me it would also be ok to have a unique constraint spanned over both fields and using a generated id.
What is the best way to get this constraint via JPA?
If your table has really two fields only, and you want they are unique, then they should be the composite PK of the table. Take a look at How to create and handle composite primary key in JPA
If, instead, you have another PK, consider Sebastian's comment.
I'm using dropwizard-hibernate and postgres (hibernate version 5.3.7)
For my DTO i have a base DTO that contains an ID fields (all DTOS extend this class)
In the database schema the Id look like this
id uuid default gen_random_uuid() not null
My configuration for the ID is like this:
#Id
#GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid2")
private UUID id;
In theory this should work but every time that i try to persist an entity i get an error saying
ERROR: relation \"hibernate_sequence\" does not exist\
I've tried everything and nothing works.. i tried just with #Id and #GeneratedValue (according to the latest hibernate documentation that should be enough for the UUID config) and many other combination of annotations but every time I try to persist the entity i get the missing sequence issue.
I know I could "fix it" just adding the hibernate_sequence table in the database but I shouldn't need it at all.
I've used this & it's worked as expected:
#Column(name = "uid")
#Generated(GenerationTime.ALWAYS)
#Type(type = "pg-uuid")
private UUID uid;
I realize that #Generated is a legacy annotation, but it seems to work.
Kindly help me to find out a solution to my problem.
I have a property of type String in my entity which is not primary key.
This would act as system generated unique profile id for users in my project.
I want to auto generate this value like a random string of particular size.
Could you please help me to arrive at a solution.
I have tried the #Generator and custom id generator class. but still null is getting inserted to the field in db.
I am using maria db.
Hi you can use the hibernate events.
#PostPersist Executed after the entity manager persist operation is actually executed or cascaded. This call is invoked after the database INSERT is executed.
Starting with Java 5, the UUID class provides a simple means for generating unique ids. The identifiers generated by UUID are actually universally unique identifiers.
Please follow the sample example.
public class TestModel {
#Column("column_name")
private String uid;
//setter and getter for uid
#PrePersist
protected void onCreate() {
// set the uid
setUid(java.util.UUID.randomUUID());
}
}
Please find the below link for more information on #PrePersist.
https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/listeners.html
I know there have been a number of similar posts about this, but I couldn't find a clear answer to my problem.
To make it as simple as possible, say I have such an entity:
#Entity
public class Person implements Serializable {
#Id
private Long id; // PK
private String name; // business key
/* getters and setters */
/*
override equals() and hashCode()
to use the **name** field
*/
}
So, id is the PK and name is the business key.
Say that I get a list of names, with possible duplicates, which I want to store.
If I simply create one object per name, and let JPA make it persistent, my final table will contain duplicate names - Not acceptable.
My question is what you think is the best approach, considering the alternatives I describe here below and (especially welcome) your own.
Possible solution 1: check the entity manager
Before creating a new person object, check if one with the same person name is already managed.
Problem: The entity manager can only be queried by PK. IS there any workaround Idon't know about?
Possible solution 2: find objects by query
Query query = em.createQuery("SELECT p FROM Person p WHERE p.name = ...");
List<Person> list = query.getResultList();
Questions: Should the objects requested be already loaded in the em, will this still fetch from database? If so, I suppose it would still be not very efficient if done very frequently, due to parsing the query?
Possible solution 3: keep a separate dictionary
This is possible because equals() and hashCode() are overridden to use the field name.
Map<String,Person> personDict = new HashMap<String,Person>();
for(String n : incomingNames) {
Person p = personDict.get(n);
if (p == null) {
p = new Person();
p.setName(n);
em.persist(p);
personDict.put(n,p);
}
// do something with it
}
Problem 1: Wasting memory for large collections, as this is essentially what the entity manager does (not quite though!)
Problem 2: Suppose that I have a more complex schema, and that after the initial writing my application gets closed, started again, and needs to re-load the database. If all tables are loaded explicitly into the em, then I can easily re-populate the dictionaries (one per entity), but if I use lazy fetch and/or cascade read, then it's not so easy.
I started recently with JPA (I use EclipseLink), so perhaps I am missing something fundamental here, because this issue seems to boil down to a very common usage pattern.
Please enlighten me!
The best solution which I can think of is pretty simple, use a Unique Constraint
#Entity
#UniqueConstraint(columnNames="name")
public class Person implements Serializable {
#Id
private Long id; // PK
private String name; // business key
}
The only way to ensure that the field can be used (correctly) as a key is to create a unique constraint on it. You can do this using #UniqueConstraint(columnNames="name") or using #Column(unique = true).
Upon trying to insert a duplicate key the EntityManager (actually, the DB) will throw an exception. This scenario is also true for a manually set primary key.
The only way to prevent the exception is to do a select on the key and check if it exists.