Entity ->
#Getter
#Setter
#NoArgsConstructor
#EqualsAndHashCode
#Entity
public class ConfirmationToken {
#SequenceGenerator(
name = "confirmation_token_sequence",
sequenceName = "confirmation_token_sequence",
allocationSize = 1
)
#Id #GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "confirmation_token_sequence"
)
private Long id;
#Column(nullable = false)
private String token;
#ManyToOne
#JoinColumn(name = "account_id", nullable = false)
private Account account;
public ConfirmationToken(String token, Account account) {
this.token = token;
this.account = account;
}
}
repository ->
#Repository
#Transactional(readOnly = true)
public interface ConfirmationTokenRepository extends
JpaRepository<ConfirmationToken, Long> {
Optional<ConfirmationToken> findByToken(String token);
}
service1 ->
public Optional<ConfirmationToken> getToken(String token) {
return confirmationTokenRepository.findByToken(token);
}
service2 ->
#Override
public String confirmToken(String token) {
ConfirmationToken confirmationToken = confirmationTokenService.getToken(token)
.orElseThrow(() -> new IllegalStateException("Token not found"));
return "Token Verified";
}
error ->
java.lang.IllegalStateException: Token not found
I checked token is in the database normally but repository still can't get the value in the database
I don't know what's causing this problem.
Related
Spring version: 5.3.19
Hibernate: 5.4.24.Final
The problem: When trying to get the List compartments from class CriticalFlight after ScrollableData gets Cleaned up #Cleanup, the list is empty since fetch was never executed.
Custom class ScrollableData execution snipped code:
List<ENTITY> filteredEntities;
#Cleanup ScrollableData<ENTITY> scrollableData =
getScrollableData(
filter,
myMarketChecker,
additionalFilters,
staticPredicateBuilders);
filteredEntities = scrollableData.getAll();
return filteredEntities;
I loop into the list returned and try to access List compartments
then got: "org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.pros.travel.services.oandd.optimizer.alerts.entity.CriticalFlight.compartments, could not initialize proxy - no Session
"
Classes
Embeddable Class: CriticalFlightKey
#Data
#Embeddable
public class CriticalFlightKey implements Serializable
{
#DTOMapping(CriticalFlightDTO.FIELD_FLIGHTDATE)
#Convert(converter = DateToLocalDateAttributeConverter.class)
#Column(name = "FLTDATE", nullable = false)
private LocalDate flightDate;
#DTOMapping(CriticalFlightDTO.FIELD_DIM_CRRCODE)
#Column(name = "CRRCODE", nullable = false)
private String carrierCode;
#DTOMapping(CriticalFlightDTO.FIELD_DIM_FLTNUM)
#Column(name = "FLTNUM", nullable = false)
private String flightNumber;
#DTOMapping(CriticalFlightDTO.FIELD_DIM_ORGN)
#Column(name = "ORGN", nullable = false)
private String origin;
#DTOMapping(CriticalFlightDTO.FIELD_DIM_DSTN)
#Column(name = "DSTN", nullable = false)
private String destination;
}
Parent Class: CriticalFlight
#Data
#EqualsAndHashCode(of = {"id"})
#Entity
#Table(name = "OD_CRITICAL_FLIGHTS")
public class CriticalFlight implements
{
#JsonUnwrapped
#EmbeddedId
#DTOMapped
public CriticalFlightKey id;
...
....
#JsonManagedReference
#OneToMany(fetch = FetchType.EAGER)
#Fetch(FetchMode.SUBSELECT)
#JoinColumns({
#JoinColumn(name="FLTDATE", referencedColumnName="FLTDATE"),
#JoinColumn(name="CRRCODE", referencedColumnName="CRRCODE"),
#JoinColumn(name="FLTNUM", referencedColumnName="FLTNUM"),
#JoinColumn(name="ORGN", referencedColumnName="ORGN"),
#JoinColumn(name="DSTN", referencedColumnName="DSTN")
})
private List<CriticalFlightCmp> compartments = new ArrayList<>();
}
Embeddable class for child: CriticalFlightCmpKey
#Data
#Embeddable
public class CriticalFlightCmpKey implements Serializable
{
#Convert(converter = DateToLocalDateAttributeConverter.class)
#Column(name = "FLTDATE", nullable = false)
private LocalDate flightDate;
#Column(name = "CRRCODE", nullable = false)
private String carrierCode;
#Column(name = "FLTNUM", nullable = false)
private String flightNumber;
#Column(name = "ORGN", nullable = false)
private String origin;
#Column(name = "DSTN", nullable = false)
private String destination;
#Column(name = "CMPCODE", nullable = false)
private String cmpCode;
}
Child Class: CriticalFlightCmp
#Data
#EqualsAndHashCode(of = {"id"})
#Entity
#Table(name = "OD_CRITICAL_FLIGHTS_CMP")
public class CriticalFlightCmp implements IPersistable<CriticalFlightCmpKey>
{
#EmbeddedId
private CriticalFlightCmpKey id;
..
...
}
Custom class ScrollableData which uses org.hibernate.ScrollableResults to execute the query
#Slf4j
public class ScrollableData<ENTITY extends IPersistable> implements Closeable
{
private static final int SCROLLABLE_FETCH_SIZE = 10000;
private final Class<ENTITY> entityClass;
private final ScrollableResults results;
private final EntityManager entityManager;
private final List<IScrollableFilter<ENTITY>> filters = new ArrayList<>();
public ScrollableData(
Class<ENTITY> entityClass,
ScrollableResults results,
EntityManager entityManager)
{
this.entityClass = entityClass;
this.results = results;
this.entityManager = entityManager;
}
/**
* Create scrollable data from a query and entity manager session.
*
* #param entityManager Entity manager from which the query was built from.
* #param query Query to scroll on.
* #return Scrollable data
*/
static <ENTITY extends IPersistable> ScrollableData<ENTITY> fromQuery(
Class<ENTITY> entityClass,
EntityManager entityManager,
CriteriaQuery query)
{
ScrollableResults results = entityManager.createQuery(query)
.unwrap(Query.class)
.setReadOnly(true)
.setFetchSize(SCROLLABLE_FETCH_SIZE)
.setCacheable(false)
.scroll(ScrollMode.FORWARD_ONLY);
return new ScrollableData<>(entityClass, results, entityManager);
}
public List<ENTITY> getAll()
{
List<ENTITY> allEntities = new ArrayList<>();
while (next())
{
allEntities.add(get());
}
return allEntities;
}
/**
* Clears the hibernate session of any entities it's caching.
*/
public void clearSession()
{
log.debug("Clearing Session for {}", entityClass.getSimpleName());
Session hibernateSession = entityManager.unwrap(Session.class);
hibernateSession.clear();
}
/**
* Closes the scrollable results and the session contained in the entity manager.
*/
public void close()
{
clearSession();
if (results != null)
{
log.debug("Closing ScrollableResults for {}",
entityClass.getSimpleName());
results.close();
}
if (entityManager != null)
{
log.debug("Clearing EntityManager for {}", entityClass.getSimpleName());
entityManager.close();
}
}
}
I want to get a list of users by username, with enabled status and has phone number. I managed to get it working till I add the phone number parameter.
here is my code:
//crud repo
List<Users> findAllByUserNameContainsAndEnabledIsAndMobileNotNull(String userName, String enabled);
// controller
public Set<User> searchByName(#PathVariable String username) throws Exception {
Set<User> result = new HashSet<>();
result.addAll(userRepository.findAllByUserNameContainsAndEnabledIsAndMobileNotNull(username, "Y"));
return result;
}
// user class
public class User{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(precision = 18, scale = 0)
private BigDecimal id;
#Column(name = "Enabled", columnDefinition = "char(1) default 'Y'")
private String enabled;
private String username;
private String mobile;
// getters setters..
What is your phone number parameter called? You said it was working until that. The names have to match.
Here is all supported keywords in the method names:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
I have started new project and everything works as expected, so the problem is not in method name. Here is code I've tested:
Entity
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(precision = 18, scale = 0)
private BigDecimal id;
#Column(name = "Enabled", columnDefinition = "char(1) default 'Y'")
private String enabled;
private String userName;
private String mobile;
public User(String enabled, String userName, String mobile) {
this.enabled = enabled;
this.userName = userName;
this.mobile = mobile;
}
}
Repositiory
public interface UserRepository extends CrudRepository<User, BigDecimal> {
List<User> findAllByUserNameContainsAndEnabledIsAndMobileNotNull(String userName, String enabled);
}
Test
#SpringBootTest
#ExtendWith(SpringExtension.class)
#ActiveProfiles("test")
class UserRepositoryTest {
#Autowired
private UserRepository userRepository;
#Test
void test_findAllByUserNameContainsAndEnabledIsAndMobileNotNull() {
User user1 = new User("Y", "user1", "mobile");
User user2 = new User("Y", "user2", null);
userRepository.save(user1);
userRepository.save(user2);
List<User> all = userRepository.findAllByUserNameContainsAndEnabledIsAndMobileNotNull("user", "Y");
System.out.println("all = " + all);
}
}
And only one record in the output:
all = [User(id=1, enabled=Y, userName=user1, mobile=mobile)]
I am having an issue where the Domain (child) is not getting the Business (parents) id. I have the business created and the domain but the domain does not have the business_id. Below is what I was doing originally. I then made a test path that I called which gave the same behavior unless I used the setBusiness method of the domain. Is this the expectation? Do I need to loop over the domains that are passed from a client and set the business?
Test
public void test() {
Business b = new Business();
b.setName("Test Test");
Domain d1 = new Domain();
d1.setName("Domain 1");
d1.setBusiness(b);
em.persist(b);
em.flush();
}
Code
#Entity
#Table(name = "Business")
public class Business {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy="business", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Domain> domains = new ArrayList<>();
//...getters and setters
}
-
#Entity
#Table(name = "Domain")
public class Domain {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "business_id", nullable = false)
private Business business;
//...getters and setters
}
I was calling a rest service using the below JSON which then persisted the business.
{
"name": "Business Test ",
"domains": [{"name": "test domain"}]
}
#Path("business")
public class BusinesResouce {
#EJB
BusinessService service;
#Path("create")
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public void create(Business entity) {
service.persist(entity);
}
//other paths
}
-
#Stateless
public class BusinessService {
private static final String PERSISTENCE_UNIT_NAME = "edc";
#PersistenceContext(unitName = PERSISTENCE_UNIT_NAME)
private EntityManager em;
public void persist(Business entity) {
em.persist(entity);
//Do I really need to loop entity.getDomains and setBusiness?
em.flush();
}
}
I know that this topic is not new, but I few days try to solve task.
I have 3 classes - Client, Account and Invoice.
Client has many Accoutns, Account has many Invoices.
I mapped them:
Client
#Entity
#Table(name = "CLIENT")
public final class Client implements Serializable {
...
#Column(length = 36, nullable = false, unique = true, updatable = false)
private String uuid;
#OneToMany(mappedBy = "client", cascade = CascadeType.ALL)
private List<Account> accounts;
...
}
Account
#Entity
#Table(name = "ACCOUNT")
public final class Account implements Serializable {
...
#ManyToOne
#JoinColumn(name = "client_uuid", referencedColumnName = "uuid", nullable = false)
private Client client;
#OneToMany(mappedBy = "account", cascade = CascadeType.ALL)
private List<Invoice> invoices;
...
}
Invoice
#Entity
#Table(name = "INVOICE")
public final class Invoice implements Serializable {
#ManyToOne
#JoinColumn(name = "account_uuid", referencedColumnName = "uuid", nullable = false)
private Account account;
}
I use Spring Data Jpa:
#Repository
public interface SpringDataClientRepository extends ClientRepository, JpaRepository<Client, Integer> {
Others the same.
When I try to run ITests, test with client work fine:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { JpaConfig.class, ITDaoConfig.class })
public class ITClientRepository {
private static final Logger log = Logger.getLogger(ITClientRepository.class);
#Autowired
private ClientRepository clientRepository;
#Test
#Transactional
public void testSaveClient() {
log.info("testSaveClient start");
Client client = new Client();
client.setName("testSaveClient");
client.setUuid("client-testSaveClient");
client.setTelephone("12345679");
Account account = new Account();
account.setClient(client);
account.setMoneyCount(10);
account.setUuid("client-testSaveClient");
client.addAccount(account);
log.info(client.toString());
Client getClient = clientRepository.save(client);
log.info(client.toString());
It saves client and account in. But this test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { JpaConfig.class, ITDaoConfig.class })
public class ITAccountRepository {
private static final Logger log = Logger.getLogger(ITAccountRepository.class);
#Autowired
private AccountRepository accountRepository;
#Test
#Transactional
public void testSaveAccount() {
log.info("testSaveAccount start");
Client client = new Client();
client.setName("testSaveAccount");
client.setTelephone("12345679");
client.setUuid("account-testSaveAccount");
client.setId(200);
// Client saved in db
Account account = new Account();
account.setClient(client);
account.setMoneyCount(15);
account.setUuid("account-testSaveAccount");
client.addAccount(account);
Invoice invoice = new Invoice();
invoice.setAccount(account);
invoice.setAmount(11);
Date date = new Date();
invoice.setCreated(date);
invoice.setUuid("account-testSaveClient");
invoice.setDescription("Description of invoice");
account.addInvoice(invoice);
log.info(account.toString());
Account getAccount = accountRepository.save(account);
log.info(account.toString());
fail with:
Caused by: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : projects.model.Invoice.account -> projects.model.Account
I want that all Invoices will be saved if I save Account of those invoices. And the same with Client - all Accounts will be saved if I save Client of them. How I do this?
I made a change to have a unidirectional relationship with composition:
Client
#Entity
#Table(name = "CLIENT")
public final class Client extends BaseEntity {
#Column(length = 36)
private String uuid;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#JoinColumn(name = "client_id", referencedColumnName = "id")
private List<Account> accounts;
}
Invoice
#Entity
#Table(name = "INVOICE")
public final class Invoice extends BaseEntity {
#Column(length = 36)
private String uuid;
}
Account
#Entity
#Table(name = "ACCOUNT")
public final class Account extends BaseEntity {
#Column(length = 36)
private String uuid;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#JoinColumn(name = "account_id", referencedColumnName = "id")
private List<Invoice> invoices;
}
In the test, I left everything like it was. And it all works now.
I have an existing JPA entity ("Reference") with an ID column as its primary key that it inherits from a base class "BaseEntity" (using the #MappedSuperclass annotation on the superclass).
I also have a 1-M relationship between a Reference and another entity called Violation. Violation was previously defined with a foreign key "REFERENCE_ID" to the "ID" column of the Reference entity.
Recently, I tried to add an unrelated composite key to the Reference entity. This should not have affected the 1-M relationship between Reference and Violation. However, when I run the code in my tomcat server, I see the following stack trace:
Caused by: org.hibernate.AnnotationException: referencedColumnNames(ID) of org.qcri.copydetection.sdk.metastore.entity.Violation.reference referencing org.qcri.copydetection.sdk.metastore.entity.Reference not mapped to a single property
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:205) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:110) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.AnnotationConfiguration.processEndOfQueue(AnnotationConfiguration.java:541) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.AnnotationConfiguration.processFkSecondPassInOrder(AnnotationConfiguration.java:523) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:380) ~[hibernate-annotations-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1206) ~[hibernate-core-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1459) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:193) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1086) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:685) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:73) ~[hibernate-entitymanager-3.5.6-Final.jar:3.5.6-Final]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:268) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:310) ~[spring-orm-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452) ~[spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE]
... 39 common frames omitted
Here is the code for the 3 classes involved:
#Entity
#Table(name = "REFERENCE")
#XmlRootElement
#XmlAccessorType(XmlAccessType.PROPERTY)
#IdClass(Reference.ContextualName.class)
public class Reference extends BaseEntity {
#Column(name= "LOCATION", unique=true)
#XmlElement
private String location;
#Id
#AttributeOverrides({
#AttributeOverride(name = "name", column = #Column(name = "NAME")),
#AttributeOverride(name = "account", column = #Column(name = "ACCOUNT_ID"))
})
#Column(name = "NAME")
#XmlElement
private String name;
#ManyToOne(optional=false)
#XmlTransient
#JoinColumn(name = "ACCOUNT_ID", referencedColumnName = "ID")
private Account account;
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Reference() {}
public Reference(String name) {
setName(name);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public Account getAccount() {
return this.account;
}
public void setAccount(Account account) {
this.account = account;
}
#Embeddable
private class ContextualName implements Serializable {
private static final long serialVersionUID = -3687389984589209378L;
#Basic(optional = false)
#Column(name = "NAME")
#XmlElement
private String name;
#ManyToOne(optional=false)
#XmlTransient
#JoinColumn(name = "ACCOUNT_ID", referencedColumnName = "ID")
private Account account;
ContextualName() {}
}
}
#MappedSuperclass
#XmlAccessorType(XmlAccessType.FIELD)
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
#XmlElement
private Long id;
#Basic(optional = true)
#Column(name = "CREATED", insertable = false, updatable = false, columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
#Temporal(TemporalType.TIMESTAMP)
#XmlElement
private Date creationDate;
protected BaseEntity() {}
public Long getId() {
return id;
}
public void setId(Long id) {
if(this.id==null) {
this.id = id;
} else if (this.id!=id) {
throw new IllegalArgumentException("Cannot change the id after it has been set, as it is a generated field.");
}
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
if(this.creationDate==null) {
this.creationDate = creationDate;
} else if (this.creationDate!=creationDate) {
throw new IllegalArgumentException("Cannot change the creation-date after it has been set, as it is a generated field.");
}
}
}
#Entity
#Table(name = "VIOLATION")
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Violation extends BaseEntity {
#ManyToOne (optional=false, fetch= FetchType.EAGER)
#JoinColumn(name = "REFERENCE_ID", referencedColumnName = "ID")
private Reference reference;
#ManyToOne (optional=false, fetch= FetchType.EAGER)
#JoinColumn(name = "SUSPECT_ID", referencedColumnName = "ID")
private Suspect suspect;
#ManyToOne (optional=false, fetch= FetchType.EAGER)
#XmlTransient
#JoinColumn(name = "SEARCH_ID", referencedColumnName = "ID")
private Search search;
#Basic(optional = false)
#Column(name = "SCORE")
#XmlElement
private double score;
public Violation() {}
public Violation(Search search, Reference ref, Suspect sus, double score) {
this.search = search;
this.reference = ref;
this.suspect = sus;
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public Reference getReference() {
return reference;
}
public void setReference(Reference reference) {
this.reference = reference;
}
public Suspect getSuspect() {
return suspect;
}
public void setSuspect(Suspect suspect) {
this.suspect = suspect;
}
public Search getSearch() {
return search;
}
public void setSearch(Search search) {
if(this.search!=null && this.search!=search) {
this.search.removeViolation(this);
}
this.search = search;
if(search!=null) {
if(!search.getViolations().contains(this)) {
search.addViolation(this);
}
}
}
}
To cut a long story short, I'm totally confused how to go about adding a composite key to an existing (legacy) entity that already has an ID column. I can't remove the ID column, nor can I change the 1-M relationship between Reference and Violation. I can't for the life of me understand the error message because the "REFERENCE_ID" foreign key column of the Violation entity is being mapped to a single "ID" column of the Reference entity.
Many thanks in advance!