location_id cannot be null while trying save using a Spring JPA 2 repository - jpa

I've a Spring JPA 2 entity class as
#Entity
#Table(name = "hotels")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Hotel {
#Id
#Column(name = "hotelId")
#JsonProperty("hotel_id")
private Integer hotelId;
#OneToOne(targetEntity = Location.class, cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
#JoinColumn(name = "location_id")
#JsonProperty("location")
private Location location;
....
}
and the Location class is given as
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
public class Location {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer location_id;
#Column
#JsonProperty("latitude")
private Double latitude;
#Column
#JsonProperty("longitude")
private Double longitude;
}
When I'm doing an hotelRepository.save(hotel) I'm getting Column 'location_id' cannot be null. I get the populated Hotel by consuming a REST web-service.
Can anyone please help me! Appreciated!

Related

JPA Repository Query on additional table #ManytoMany

I want to do select like this in my jpa spring repository
SELECT sicknes_id, count(symptomp_id) as ilosc FROM symptomp_sicknes where symptomp_id IN (1,2) group by sicknes_id Order by ilosc DESC;
My enitity
#Entity
#Table(name = "symptomp")
public class Symptomp {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "symptomp_id")
private Long symptomp_id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#ManyToMany(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}, fetch = FetchType.LAZY)
#JoinTable(name = "symptomp_sicknes",joinColumns = #JoinColumn(name = "symptomp_id"),inverseJoinColumns = #JoinColumn(name = "sicknes_id"))
private Set<Sicknes> sicknes = new HashSet<>();
#Entity
#Table(name = "sicknes")
public class Sicknes {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sicknes_id")
private Long sicknes_id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#ManyToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}, fetch = FetchType.LAZY)
#JoinColumn(name = "speciesId")
private Species species;
My Symptomp repository:
public interface SymptompRepository extends JpaRepository<Symptomp, Long> {
#Query("select p from Symptomp p where name like ?1%")
public List<Symptomp> findAllBySymptompName(String symptomp);
public Symptomp findByName(String symptomp);
public List<Symptomp> findByNameIn(List<String> list);
Integer countDistinctSymptompByName(String id);
}
How I can create this select in my JPA repository?
I try get value like in select but i got error mapping bean.
You can get query result as List<Object[]> using nativeQuery=true parameter
#Query("SELECT sicknes_id, count(symptomp_id) as ilosc FROM symptomp_sicknes where symptomp_id IN (1,2) group by sicknes_id Order by ilosc DESC", nativeQuery=true)
List<Object[]> getQueryResult();
Other option is to create dto class with appropriate constructor
public class QueryResultDto {
Long sicknesId;
Long count;
public QueryResultDto(Long sicknesId, Long count) {
this.sicknesId = sicknesId;
this.count = count;
}
}
Then using JPQL
#Query("select new yourproject.dtopath.QueryResultDto(...")
List<QueryResultDto> getQueryResult(#Param("symptompIds") List<Long> symptompIds);
If you want to avoid a native Query the best way is to create an Entity for that JoinTable. Then you can query it easily. Additional benefit if this is that if in future a requirement will pop up that you have to store additional attributes in that relation you will have the Entity already there to do that easily.

Spring Data Envers Entity must not be null

Suppose we have audited entities with #OneToOne relation:
#Entity
#Audited
#Table(name = "product")
public class Product {
#Id
#GeneratedValue
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "active")
private boolean active;
#OneToOne(mappedBy="product", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private ProductPrice productPrice;
}
#Audited
#Entity
#Table(name = "product_price")
public class ProductPrice {
#Id
#GeneratedValue
#Column(name = "id")
private Long id;
#Column(name = "amount")
private Long amount;
#OneToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "product_id", nullable = false)
private Product product;
}
And RevisionService with the method to get revisions and find changes:
#Transactional
public Page<Revision<Long, Product>> getGroupRevisions(Long productId, int page) {
Page<Revision<Long, Product>> revisions = productRepository.findRevisions(productId, PageRequest.of(page, 5, RevisionSort.desc()));
Long priceId = revisions.getContent().get(0).getEntity().getProductPrice().getId();
Page<Revision<Long, ProductPrice>> priceRevisions = productPriceRepository.findRevisions(priceId, PageRequest.of(page, 5, RevisionSort.desc()));
return revisions;
}
Now, If I create new Product and ProductPrice records and then make changes into Product more then 5 times (5 RevInfo records would generated), I get exception:
java.lang.IllegalArgumentException: Entity must not be null!
at org.springframework.util.Assert.notNull(Assert.java:198)
at org.springframework.data.history.AnnotationRevisionMetadata.<init>(AnnotationRevisionMetadata.java:55)
at org.springframework.data.envers.repository.support.EnversRevisionRepositoryImpl.getRevisionMetadata(EnversRevisionRepositoryImpl.java:237)
at org.springframework.data.envers.repository.support.EnversRevisionRepositoryImpl.lambda$toRevisions$1(EnversRevisionRepositoryImpl.java:223)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.HashMap$EntrySpliterator.forEachRemaining(HashMap.java:1837)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at org.springframework.data.envers.repository.support.EnversRevisionRepositoryImpl.toRevisions(EnversRevisionRepositoryImpl.java:226)
at org.springframework.data.envers.repository.support.EnversRevisionRepositoryImpl.getEntitiesForRevisions(EnversRevisionRepositoryImpl.java:196)
at org.springframework.data.envers.repository.support.EnversRevisionRepositoryImpl.findRevisions(EnversRevisionRepositoryImpl.java:163)
After debugging I saw that this "null" entity was proxied by Hibernate and Spring Data envers could not resolve revision number in this point:
Number revNo = this.enversService.getRevisionInfoNumberReader().getRevisionNumber(revision);
Here is the link to github test project: https://github.com/aquariusmaster/spring-data-envers-bug
So my question is this a bug in Spring Data Envers or I miss something in the configuration?
As spring-data-envers team replied, upgrading boot version to 2.3.1.RELEASE solve the problem:
https://github.com/spring-projects/spring-data-envers/issues/34#issuecomment-651681687

Spring data : issue with OneToOne relationship

I am developping a webapp (Spring J2EE/angularjs)
I want to set a relationship between two entities :
citizen (id, lastName, city)
city (id, cityName)
A citizen live in only one city.
I need to find a city from a citizen.
I don't need to find a citizen from a city.
I have done that :
#Entity
#Table(name = "citizen")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Citizen implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "last_name")
private String lastName;
#OneToOne
private City city;
}
#Entity
#Table(name = "city")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class City implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "city_name")
private String cityName;
}
In database I have inserted data. Citizen 1, 2 and 3 are linked to City 1
and Citizen 4 is linked to City 2
When I try to load all citizen, I am getting the error:
More than one row with the given identifier was found: 1, for class: com.myApp.rh.domain.Citizen
What's wrong in my entities?
Thanks
It seems that you are missing the #JoinColumn annotation in your Citizen entity.
#Entity
#Table(name = "citizen")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Citizen implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "last_name")
private String lastName;
#OneToOne
#JoinColumn(name = "id", unique = true)
private City city;
}
#Entity
#Table(name = "city")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class City implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "city_name")
private String cityName;
}

JPA OneToOne not working

I followed by tutorial : http://www.codejava.net/frameworks/hibernate/hibernate-one-to-one-mapping-with-foreign-key-annotations-example
I have following code:
#Entity
#Table(name = DomainConstant.TABLE_USER)
public class User{
#Id
#Column(name = DomainConstant.DOMAIN_USER_ID)
#GeneratedValue
private Long userId;
private UserActivationCode userActivationCode;
///////////////////// CONSTRUCTOR....
/// STANDARD GET AND SET....
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = DomainConstant.DOMAIN_ACTIVATION_LINK_ID)
public UserActivationCode getUserActivationCode() {
return userActivationCode;
}
}
#Entity
#Table(name = DomainConstant.TABLE_USER_ACTIVATON_LINK)
public class UserActivationCode {
#Id
#Column(name = DomainConstant.DOMAIN_ACTIVATION_LINK_ID)
#GeneratedValue
private Long userActivationCodeId;
#Column(name = DomainConstant.DOMAIN_ACTIVATION_DATE)
#Temporal(javax.persistence.TemporalType.DATE)
private Date date;
#Column(name = DomainConstant.DOMAIN_ACTIVATION_CODE)
private String code;
///////////////////// CONSTRUCTOR....
/// STANDARD GET AND SET....
}
When I save the User object it does not make record in UserActivationCode, why?
Like this:
User newUser = new User();
newUser.setUserActivationCode(new UserActivationCode("this is example"));
userDao.save(newUser);
I have record only in user table.
Can you tell me why?
Your problem is that you are mixing access types. In the User entity you have specified #Id on a field (private Long userId) whereas you have defined the join mapping on a property (the getter to UserActivationCode). If you specify the join mapping on the field, it should work as is.
#Entity
#Table(name = DomainConstant.TABLE_USER)
public class User{
#Id
#Column(name = DomainConstant.DOMAIN_USER_ID)
#GeneratedValue
private Long userId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = DomainConstant.DOMAIN_ACTIVATION_LINK_ID)
private UserActivationCode userActivationCode;
///////////////////// CONSTRUCTOR....
/// STANDARD GET AND SET....
public UserActivationCode getUserActivationCode() {
return userActivationCode;
}
}
For more information on access and access types, see Access, Java EE 7

Exception while persisting JPA object in DB having one to many relation

hi have two tables in picture table a and table b as follows :
#Entity
#Table(name = "A")
public class A implements Serializable {
#Id
#SequenceGenerator(name = "JOURNAL_CATEGORY_ID_GENERATOR", allocationSize = 1, sequenceName = "clm_jounal_category_config_seq")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "JOURNAL_CATEGORY_ID_GENERATOR")
#Column(name = "CLAIM_ID")
private String claimId;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "country")
private List<ClaimDTLS> claimDetails;
}
B Primary Key:
#Embeddable
public class BPK implements Serializable {
#Column(name = "code")
private String code;
#Column(name = "CLAIM_ID")
private String claimId;
}
B Entity:
#Entity
#Table(name = "B")
public class B implements Serializable {
#EmbeddedId
protected BPK bpk;
#Column(name = "name")
private String name;
#MapsId("country_code")
#JoinColumn(name = "claimId", referencedColumnName = "claimId", insertable = false, updatable = false)
#ManyToOne
private A a;
}
when i try to persist object of A type in Db the value of table b claim id is not set and is intialized with zero.
Also primary key of table A is generated with a oracle sequence.
any help will be welcomed.
thanks in advance
Sequence values are numbers and when JPA use them as a generator it call the setter method of the entity PK. Now, you defined your PK as a string while you use a sequence and so no matching setter can be found. Change the type of you PK to be Long and things shall work