I am running into a NucleusUserException while querying my google datastore instance. I am querying for a field that exists on a MappedSuperclass on the class that extends it. Here is my abstract class that contains the field I am interested in:
#Entity
#MappedSuperclass
#JsonIgnoreProperties({ "password" })
public abstract class AbstractUser implements User {
#Persistent
protected String emailAddress;
public void setEmailAddress(String email) {
this.emailAddress = email;
}
public String getEmailAddress() {
return this.emailAddress;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long key;
//Other stuff.
}
The concrete instance looks like this:
#Entity
public class Client extends AbstractUser {
//Things that only clients have.
}
My query that is failing looks like this:
List existingUsersWithEmail = manager
.createQuery(
"SELECT c from Client AS c WHERE c.emailaddress = :mail")
.setParameter("mail", request.getEmailAddress())
.getResultList();
The exception is this:
Cannot access field emailaddress on type org.workouthound.user.Client
org.datanucleus.exceptions.NucleusUserException: Cannot access field emailaddress on type org.workouthound.user.Client
at org.datanucleus.query.compiler.JavaQueryCompiler.getType(JavaQueryCompiler.java:552)
at org.datanucleus.query.compiler.JavaQueryCompiler.getType(JavaQueryCompiler.java:529)
at org.datanucleus.query.symbol.SymbolTable.getType(SymbolTable.java:118)
at org.datanucleus.query.expression.PrimaryExpression.bind(PrimaryExpression.java:118)
at org.datanucleus.query.expression.DyadicExpression.bind(DyadicExpression.java:85)
at org.datanucleus.query.compiler.JavaQueryCompiler.compileFilter(JavaQueryCompiler.java:299)
at org.datanucleus.query.compiler.JPQLCompiler.compile(JPQLCompiler.java:75)
at org.datanucleus.store.query.AbstractJPQLQuery.compileInternal(AbstractJPQLQuery.java:246)
at org.datanucleus.store.query.Query.setImplicitParameter(Query.java:690)
at org.datanucleus.jpa.JPAQuery.setParameter(JPAQuery.java:428)
at org.workouthound.rest.client.UserResources.emailIsRegistered(UserResources.java:55)
at org.workouthound.rest.client.UserResources.createClient(UserResources.java:33)
I am new to DataNucleus and Google Data Store. I attempted to follow the tutorial as outlined here however I very well could have missed something. Please let me know as additional information is necessary.
UPDATE:
If I change the field name to email as well as the getters, setters and query, it works...why?
Related
In my Spring boot batch application, I am calling a JPA repository class from Tasklet.
The JPA call retrieves a particular value (Entity object) from DB. The problem is, If I update some value in the entity object, once the control goes out of Tasklet, it automatically updates to DB even though I am not calling any save operation. How to prevent this? Default JPA implementation is Hibernate.
Tasklet class
Employee employee = employeeRepository.fetchEmployee(employeeName);
List<Address> addressList = employee.getAddress();
addressList.forEach(e -> e.setStatus(Status.INVALID.toString()));
Repository
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
#Query("select em from Employee em where em.employeeName = :employeeName")
public Employee fetchEmployee(#Param("employeeName") Long employeeName);
}
Entity class
#Entity
#Table(name = "Employee")
public class Employee implements java.io.Serializable {
private static final long serialVersionUID = -3769636546619492649L;
private Long id;
private List<Address> address;
private String employeeName;
// Getters and setters
// #OneToMany mapping to Address
}
Even though I am not calling a .save() operation, it automatically updates Address table Status to "INVALID"
This happen because the entity is not in detached state. In EJB we can do this in the following way.
EJB solution
#Query(value = "select * from Employee WHERE EmployeeName = ?1", nativeQuery = true)
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public List<Employee> fetchEmployee(String employeeName);
This will make the transaction closed. Changes you make to entity will not get saved in DB
Spring JPA
After a bit of research i found JPA doesn't provide the detach functionality out of the box.
Refer : https://github.com/spring-projects/spring-data-jpa/issues/641
To make it work we can have a custom JPA repository which overrides detach method. An example is given in this link.
https://www.javaer101.com/en/article/1428895.html
Use Deep cloning to solve your issue.
First override the clone method inside your Address class like below.
Note : Please customize the implementation of clone() method by adding your class attributes.Since you didn't mention the structure of the class Address , I have implemented the solution with my own defined class attributes.
Address class
public class Address {
private String country;
private String city;
private String district;
private String addressValue;
public Address() {
super();
}
public Address(String country, String city, String district, String addressValue) {
super();
this.country = country;
this.city = city;
this.district = district;
this.addressValue = addressValue;
}
//Getters and Setters
#Override
protected Object clone() {
try {
return (Address) super.clone();
} catch (CloneNotSupportedException e) {
return new Address(this.getCountry(), this.getCity(), this.getDistrict(),this.getAddressValue());
}
}
}
Then re construct your class Tasket like below.
Tasket Class
Employee employee = employeeRepository.fetchEmployee(employeeName);
List<Address> addressList = employee.getAddress();
List<Address> clonedAddressList = new ArrayList<>();
addressList.forEach(address -> clonedAddressList.add((Address)address.clone()) );
clonedAddressList.forEach(address -> address.setStatus(Status.INVALID.toString()));
Bear with me for any mistakes I make, as this is my first question here.
I have a database with two tables, one table called: PERSON
with the following entity:
#Entity
class Person {
#Id
private String guid;
private String firstName;
private String organisationGuid;
...
...
}
And one table called: ORGANISATION
with the following entity:
#Entity
class Organisation {
#Id
private String guid;
private String name;
...
...
}
As you can see, every Person belongs to an Organisation.
And now I need to list all my persons, with the name of the organisation. I do not want the full Organisation-entity on the Person-entity, rather just the name. Like so:
[{
"guid": "xxx",
"firstName": "Name",
"organisationGuid": "yyy",
"organisationName": "Name of yyy"
}]
How can I accomplish this in the easiest way possible?
Things I have already tried:
1) Adding property to Person and modyfing select-statement
#Entity
class Person {
#Id
private String guid;
private String firstName;
private String organisationGuid;
private String organisationName;
...
...
}
--
#Repository
public interface PersonRepository extends CrudRepository<Person, String> {
#Query(nativeQuery = true, value = "select p.*, o.name as organisation_name from person p left join organisation o on p.organisation_guid = o.guid")
List<Person> findAll();
}
Result: This works fine when using findAll but as soon as I try to save a Person I get an error stating that column ORGANISATION_NAME does not exist.
2) OK, makes sense, so I tried to put #Transient on the field in the entity
#Entity
class Person {
...
#Transient
private String organisationName;
...
...
}
Result: Now it works to save the entity, but I never get the organisationName (as it is marked as Transient).
3) Well damn, then I try to use the annotation #ReadOnlyProperty
#Entity
class Person {
...
#ReadOnlyProperty
private String organisationName;
...
...
}
Result: Same error as in (1). I can findAll but as soon as I try to save a person entity hibernate reports that the column does not exist (because in order to save an item, hibernate first needs to select it, and this particular select does NOT use my own custom select I created in the repository).
4) So then I created a class called PersonOrganisation (with #Table(name="organisation")) with a #ManyToOne-relation from Person to PersonOrganisation, where PersonOrganisation is an entity with just two fields, guid and name.
Result: Error. I can findAll but as soon as I try to save a person entity hibernate reports that the organisationGuid does not match a PersonOrganisation in the database (as it seems that PersonOrganisation is not an Organisation the way Hibernate sees it).
Many things that can be improved here:
1) Add a relationship in the Person relating to the Organization:
#Entity
class Person {
#Id
private String guid;
private String firstName;
#ManyToOne
#JoinColumn(name = "organisationGuid")
private Organisation organisation;
2) create a Result Class which would be holding the projection results:
package com.mypkg;
#Entity
class PersonOrganization {
private String guid;
private String firstName;
private String organisationGuid;
private String organisationName;
public PersonOrganization(String guid, String firstName
, String organisationGuid, String organisationName){
// set the fields
}
}
3) Change the query (dont use native.. its not necessary):
#Repository
public interface PersonRepository extends CrudRepository<Person, String> {
#Query("select NEW com.mypkg.PersonOrganization(p.guid as guid ...
, o.name as organisationName)
from person p left join p.organisation o")
List<PersonOrganization> findPersonWithOrganization();
}
Remeber to add aliases to each result column to match the consturctor of the PersonOrganization class.
I started using the solution from Maciej above, but ran into problems when I didn't want to create an extra "projection" entity with the same fields as the original entity (there were 20 additional fields the on Person entity).
So I actually found another solution which I am very happy with.
1) I started out with adding a #ManyToOne in Person (like Maciej suggested)
#Entity
public class Person {
#Id
private String guid;
private String firstName;
#ManyToOne
private Organisation organisation;
...
...
}
2) I also added a custom serializer to the get-method for the Organisation on the Person entity:
#JsonSerialize(using = OrganisationLightSerializer.class)
public Organisation getOrganisation() {
return organisation;
}
The custom serializer is super simple:
public class OrganisationLightSerializer extends JsonSerializer<Organisation> {
#Override
public void serialize(Organisation organisation, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("name", organisation.getName());
jsonGenerator.writeEndObject();
}
}
3) Then I changed all find-queries in my repository and added join fetch, and with this I stopped hibernate from using (at least) two SQL-queries when fetching a list of Persons:
#Repository
public interface PersonRepository extends CrudRepository<Person, String> {
#Override
#Query("select p from Person p join fetch p.organisation o")
List<Person> findAll();
}
Result: I did not get the JSON-structure exactly the way I wanted it, but I managed to get just the pertinent information from each Organisation on each Person. The resulting JSON when fetching persons looks like so (as you can see I skipped the guid of the Organisation in the end, but it can easily be added again by just changing the custom serializer):
[{
"guid": "xxx",
"firstName": "Name",
"organisation": { name: "Name of yyy"}
}]
Disclaimer: Now I realize that my response here is not an exact answer to my own query, as I stated I wanted the JSON as a flat structure, but having an Organisation object in the JSON, which only contains the name of the Organisation is almost as good a solution. Should I edit/change/comment the question so that it reflects the actual answer here, or is this minor change an "acceptable" deviation of the requirements.
I'm using the javax.persistence package to map my Java classes.
I have entities like these:
public class UserEntity extends IdEntity {
}
which extends a mapped superclass named IdEntity:
#MappedSuperclass
public class IdEntity extends VersionEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// Getters and setters below...
}
The IdEntity super class extends another mapped super class named VersionEntity to make all entities inherit version properties:
#MappedSuperclass
public abstract class VersionEntity {
#Version
private Integer version;
// Getters and setters below...
}
Why?
Because now I can make generic queries on the IdEntity class for all entities, and it will look like this: (example)
CriteriaBuilder builder = JPA.em().getCriteriaBuilder();
CriteriaQuery<IdEntity> criteria = builder.createQuery(IdEntity.class);
Now to the problem.
Some of my entities will have timestamps like created_at and deleted_at. But not all entities.
I could provide these properties in my entity classes like this:
public class UserEntity extends IdEntity {
#Basic(optional = false)
#Column(name = "updated_at")
#Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
}
But as I have a lot of entities, this will make me put a lot of redundant code in all entities that should have timestamps. I wish there was some way I could make the relevant classes inherit these fields in some way.
One possible solution is to create a parallell IdEntity superclass, maybe named IdAndTimeStampEntity and make those entities that should have timestamps inherit from this new superclass instead, but hey that's not fair to my colleague-developers because now they have to know which super class to choose from when writing generic queries:
CriteriaBuilder builder = JPA.em().getCriteriaBuilder();
CriteriaQuery<???> criteria = builder.createQuery(???); // Hmm which entity should I choose IdEntity or IdAndTimeStampEntity ?? *Annoyed*
And the generic entity queries become not so generic..
My question: How can I make all of my entities inherit id and
version fields, but only a sub part of all entities inherit
timestamp fields, but keep my queries to a single type of entities?
Update #1
Question from Bolzano: "can you add the code which you specify the path(holds table info) for entities ?"
Here is a working example of querying a UserEntity which is a IdEntity
CriteriaBuilder builder = JPA.em().getCriteriaBuilder();
CriteriaQuery<IdEntity> criteria = builder.createQuery(IdEntity.class);
Root<IdEntity> from = criteria.from(IdEntity.class);
criteria.select(from);
Path<Integer> idPath = from.get(UserEntity_.id); //generated meta model
criteria.where(builder.in(idPath).value(id));
TypedQuery<IdEntity> query = JPA.em().createQuery(criteria);
return query.getSingleResult();
I would pick a solution that didn't enforce a class-based object model like you've outlined. What happens when you don't need optimistic concurrency checking and no timestamps, or timestamps but no OCC, or the next semi-common piece of functionality you want to add? The permutations will become unmanageable.
I would add these common interactions as interfaces, and I would enhance your reusable find by id with generics to return the actual class you care about to the caller instead of the base superclass.
Note: I wrote this code in Stack Overflow. It may need some tweaking to compile.
#MappedSuperclass
public abstract class Persistable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// getter/setter
}
public interface Versioned {
Integer getVersion();
}
public interface Timestamped {
Date getCreated();
Date getLastUpdated();
}
#Embeddable
public class TimestampedEntity {
#Column(name = "create_date")
#Temporal
private Date created;
#Column
#Temporal
private Date lastUpdated;
// getters/setters
}
#Entity
public class UserEntity extends Persistable implements Versioned, Timestamped {
#Version
private Integer version;
#Embedded
private TimestampedEntity timestamps;
/*
* interface-defined getters. getTimestamps() doesn't need to
* be exposed separately.
*/
}
public class <CriteriaHelperUtil> {
public <T extends Persistable> T getEntity(Class<T> clazz, Integer id, SingularAttribute idField) {
CriteriaBuilder builder = JPA.em().getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(clazz);
Root<T> from = criteria.from(clazz);
criteria.select(from);
Path<Integer> idPath = from.get(idField);
criteria.where(builder.in(idPath).value(id));
TypedQuery<T> query = JPA.em().createQuery(criteria);
return query.getSingleResult();
}
}
Basic Usage:
private UserEntity ue = CriteriaHelperUtil.getEntity(UserEntity.class, 1, UserEntity_.id);
ue.getId();
ue.getVersion();
ue.getCreated();
// FooEntity implements Persistable, Timestamped
private FooEntity fe = CriteriaHelperUtil.getEntity(FooEntity.class, 10, FooEntity_.id);
fe.getId();
fe.getCreated();
fe.getVersion(); // Compile Error!
#MappedSuperclass
public class IdEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Version
private Integer version;
}
#MappedSuperclass
public class IdAndTimeStampEntity extends IdEntity{
Date created;
}
#Entity
public class UserEntity extends IdAndTimeStampEntity{
String name;
}
#Entity
public class FooEntity extends IdEntity{...
Pros of this solution:
In simple and clear way uses OOP without need to embed duplicate code implementing intefaces in every subclass. (Every class is also interface)
Optimistic locking version column is mostly used approach. And should be part of base class. Except read only entities like codetables.
Usage:
public <T extends IdEntity> T persist(T entity) {
if (entity instanceof IdAndTimeStampEntity) {
((IdAndTimeStampEntity) entity).setCreated(new Date());
}
if (!em.contains(entity) && entity.getId() != null) {
return em.merge(entity);
} else {
em.persist(entity);
return entity;
}
}
I wish there was some way I could make the relevant classes inherit these fields in some way.
You could make a custom annotation #Timed and use an annotation processor to add the timestamp field and annotations, either by using a bytecode manipulation framework or creating a delegating subclass. Or, for example if you use Lombok, create a Lombok annotation.
That way, your team members only have to remember to use the #Timed annotation when you have entities with timestamps. Whether you like such approach or not is up to you.
I'm very new in Spring Framework, I want to know if is possible invoke Entity Named Query only defining the Named Query on the interface without any implementation.
I want to do something like this.
NamedQuery(name = "StateBo.findByCountry", query = "SELECT state FROM StateBo state WHERE state.country.id = ?")
#Table(name = "STATE")
#Entity(name = "StateBo")
public class StateBo extends BaseNamedBo {
private static final long serialVersionUID = 3687061742742506831L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "STATE_ID")
private Long id;
#Column(name = "ISO_CODE")
private String isoCode;
#ManyToOne
#JoinColumn(name = "COUNTRY_ID")
private CountryBo country;
// getters and setters ...
}
I defined the Named Query StateBo.findByBCountry, my interface looks like this
public interface IStateDao extends JpaRepository<StateBo, Long> {
public List<StateBo> findByCountry(Long id);
}
And the interface implementation looks like this.
#Transactional
#Repository("stateDao")
public class StateDao implements IStateDao {
}
But I have the error that I have to implement the methods that I'm defining on my interface, but I don't want to do that. I only want define my Named Query and define the method in my interface with the same name that is on the Entity and don't add the implementation of that method because the implementation is basically the String Named Query
You can use Spring Data Jpa project.
For start you see https://spring.io/guides/gs/accessing-data-jpa/
To execute query without an implementation(only interface) see http://docs.spring.io/spring-data/jpa/docs/1.6.0.RELEASE/reference/htmlsingle/#jpa.query-methods.at-query
Basically you don't need the implementation:
#Transactional
#Repository("stateDao")
public class StateDao implements IStateDao {
}
try to remove that and see what will happen.
I working on a requirement where user enters a text and I need to show matching data on screen.
I am using EclipseLink as JPA provider.
Following is the code
#Entity
#Table(name="customer")
public class Customer{
private List<Address> addresses = new ArrayList<Address>();
//other code
}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "type")
#Table(name="address")
public abstract class Address{
private String name;
}
#Entity
public class PostalAddress extends Address{
private Contact number;
}
public class Contact{
private String number;
public Contact(String number){
this.number = number;
}
}
In DataBase I have table 'address' in which I have columns 'name' and 'number'.
I want to create a Predicate using CriteriaBuilder to search a specific value in table.
I have tried using
criteriabuiler.like(criteriabuiler.lower(root.join("addresses", JoinType.LEFT).<String>get("number")), searchString));
But it gives exception as
The attribute [msisdn] from the managed type [EntityTypeImpl#27575562:Address] is not present.
Can you please suggest a way to implement this thing?