I have an entity that is being saved with a MongoRepository. The class has a property Id annotated with #Id:
public class KCItem {
#Id
private String id;
When saved it generates a long id - 5bb390b88ba5b9248ad148ce. These ids will be part of URLs and I'd like them to be shorter (I don't expect to have more than 1 million total items). What would be a better way to either replace Id with a shorter value OR create a second attribute that is the short id?
Related
I'm using JPA, Hibernate and Postgres. I'd like the code to be as solution neutral as possible, where JPA is a given.
My simplified entity looks like this:
#Entity
#Table(name = "example")
public class ExampleEntity {
#Id
#GeneratedValue
private UUID id;
private String businessId; //format is YYYY000001 where YYYY = current year. Current assumption: number is incrementing and reset every year, number is always filled up with leading 0 to make the key 10 digits
}
I always have a generated UUID as the primary key. The business-id shall only be set if a certain state has been reached and is therefore unrelated to when the entity has been created. I would like the database to take care of the incrementing number.
Preferably I'd like to solve this through JPA, but also see a "dirtier" solution where I fetch the sequence-id and generate the business-key in my logic.
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 have a model like the one below (assume as pseudo code )
class Student {
#Id
private String id;
private String firstname;
.....;
#DBRef(lazy=true)
private College college
// getters and setters
}
class College {
#Id
private String id;
private String name;
// other attributes.
// getters and setters
}
I am using #DBRef(lazy=true) so that I do not load the college associated with the student. For example: if I have a repository method for Student called findByFirstname(String firstname), I can load the student without the college.
However, at times I would also want to load the student with college. Is it possible to write a repository method with a custom query using the #Query annotation (org.springframework.data.mongodb.core.query.Query) where I can load the student (all fields) and also the associated college instance ?
#Query( what should go here ?)
Student findStudentWithCollege(String firstname)
If no, then what would be a suggested way to load lazy documents on demand ?
As per the documentation
"DBRefs can also be resolved lazily. In this case the actual Object or Collection of references is resolved on first access of the property. Use the lazy attribute of #DBRef to specify this. Required properties that are also defined as lazy loading DBRef and used as constructor arguments are also decorated with the lazy loading proxy making sure to put as little pressure on the database and network as possible." I guess this may not be suitable for cases where one would want to load a student whose last name is "Smith" along with the college instance for each of the students retrieved.
I'm working on a JavaEE application with EJB and JPA.
My Entities, are defined, for instance, like this:
#Entity
public class Utente implements Serializable {
#Id
#GeneratedValue
private int cod_utente;
private String nome_utente;
private String morada_utente;
#Temporal(TemporalType.DATE)
private GregorianCalendar dnasc_utente;
private int tel_utente;
private List<GregorianCalendar> agenda;
#OneToMany
#JoinColumn(nullable=true)
private List<Prescricao> lista_presc;
When I create entities Utente, the keys are generated sequentially starting from one. If I shut down the clients and server and execute them again, the "counter" of the key generator is reestablished. This results in an error because the application will try to create another Utente with primary key "1".
Can please someone help me solve this problem?
The code:
#Id
#GeneratedValue
private int cod_utente;
doesn't set a specific stategy to generate the values for the ID.
It is the same as this code:
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int cod_utente;
GenerationType.AUTO means that the persistence provider (in Glassfish the default persistence provider is EclipseLink) should choose an appropriate strategy for the database you are using. It looks like the persistence provider is choosing a strategy which is restarting the values after a server restart in your case.
There are different generation strategies, you can find some detailed information in the EclipseLink Wiki.
I guess your best bet is to use a database sequence (GenerationType.SEQUENCE) to generate the ID values.
Example:
Create a database sequence named GEN_SEQUENCE (if you let the persistence provider generate your tables I guess you can also let it create the sequence somehow but this example will show how to do it manually), you should look for information on how to do that in the database you are using (probably something like CREATE SEQUENCE gen_sequence;). Change your code to this:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq_gen")
#SequenceGenerator(name = "my_seq_gen", sequenceName = "GEN_SEQUENCE")
private int cod_utente;
You can also use the same sequence for different classes.
Update:
For the #SequenceGenerator you can set an allocationSize, this value is the amount of sequence values which get reserved. The default value is 50. When you have a sequence which starts at 0, the first time a value is requested from the sequence, the sequence allocates (and reserves) the values 0-49 (or 1-50). These values can be used by the persistence provider until all values have been used, then the next 50 values (50-99 or 51-100) will get allocated and reserved. The sequence remembers the current position, so that it doesn't give out the same range twice if it is used by multiple classes.
For the value of the allocationSize you can keep the default, but this may produce gaps in the IDs. If a sequence range (e.g. 0-49) gets allocated (reserved) and only one or some of the values are used (e.g. 0, 1 and 2) the other values of this range (3-49) will get "lost" on server restart. The next time a range of values is allocated it will be 50-99, so the next ID in your table will be 50.
Now you have the following IDs in your table: 0,1,2,50. Normally this shouldn't be a problem, but you can also set the allocationSize to a lower value or to 1 to avoid creating such gaps.
See also:
what is the use of annotations #Id and #GeneratedValue(strategy = GenerationType.IDENTITY)? Why the generationtype is identity?
what is sequence (Database) ? When we need it?
The differences between GeneratedValue strategies
I'm still trying to get my hands around mongodb and how best Entities can be mapped. if you take for example: the entity user and the entity addresses. there could be one-to-many when someone is coming from jpa background. Here in mongo i don't want to use dbref. So addresses are in a Set collection in user.
Supposing i was using spring-data-mongo:
Question 1 : should both User and Address have the #Document annotation?Or just User?
Question 2 : what is the best way to query for addresses of a user. It is possible at first place? Because right now I query to get the User by username or Id and then get the addresses of the user.Can I query directly for sub-document? if yes how is it done using spring-data-mongo Criteria Query:
#Document
public class User{
#Id
private Long ID;
private String username;
private Set<Address> addresses = new HashSet<Address>();
...
}
#Document
public class Address {
#Id
private Long ID;
private String city;
private String line1;
...
}
Question 1: No, #Document is not strictly necessary at all. We just leverage this on application startup if you activate classpath-scanning for document classes. If you don't the persistence metadata scanning will be done on the first persistence operation. We traverse properties of domain objects then, so Address will be discovered.
Question 2: You'll have to read the User objects entirely as MongoDB currently does not allow returning sub-documents. So you'll have to query for the entire Userdocument but can restrict the fields being returned to the addresses field using a fieldSpec on the Query object or the repository abstraction's #Query annotation (see ref docs).