Can not query for non basic attributes JPA - jpa

I have a DBTweet class which knows it's comments as list of other DBTweet-objects (#OneToMany) and which knows it's parent tweet (#ManyToOne) if it is a comment. Parent is set to null if the tweet is no comment.
#Entity
#XmlRootElement
public class DBTweet extends DBIdentified {
#Basic
Date publishedOn;
#Basic
String username;
#Basic
String text;
#Basic
boolean isAnswer;
#OneToMany(mappedBy = "parent")
List<DBTweet> answers = new ArrayList<>();
#ManyToOne
DBTweet parent = null;
}
When i want to query for all tweets, that are no comments i want to use this query
#GET
#Path("/tweet/newestfirst")
#Produces(MediaType.APPLICATION_JSON)
public Response readNewestTweet() {
final CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
final CriteriaQuery<DBTweet> query = builder.createQuery(DBTweet.class);
final Root<DBTweet> from = query.from(DBTweet.class);
final Predicate predicate = builder.isNull(from.get(DBTweet_.parent));
final Order order = builder.desc(from.get(DBTweet_.publishedOn));
query.select(from).where(predicate).orderBy(order);
return Response.ok(this.entityManager.createQuery(query).getResultList()).build();
}
But the non-basic properties of DBTweet are not known by the compiler.
It just says:
cannot find symbol
symbol: variable parent
location: class de.ls5.wt2.DBTweet_
In the compiled file there are only the basic properties.
#StaticMetamodel(DBTweet.class)
public abstract class DBTweet_ extends DBIdentified_ {
public static volatile SingularAttribute<DBTweet, Date> publishedOn;
public static volatile SingularAttribute<DBTweet, String> text;
public static volatile SingularAttribute<DBTweet, String> username;
public static volatile SingularAttribute<DBTweet, Boolean> isAnswer;
public DBTweet_() {
}
}
Why can't i find the answers or parent property in the compiled file?
How can i solve this?
Any ideas?

Related

Eclipselink translatedsqlstring exception

I have a simple JPA entity with #AdditionalCriteria mentioned for the login language. I also have specified a query redirector for this class. When I attempt to get the translated sql string in the query redirector, I get a null pointer exception. The reason is that the field in the entity is called lang and the additional criteria parameter is LOGIN_LANGUAGE. The exception is thrown when the line 273 of class org.eclipse.persistence.internal.expressions.ParameterExpression is executed.
My JPA entity looks like this
#QueryRedirectors(allQueries=VPMQueryRedirector.class)
#AdditionalCriteria(value = "this.lang = :LOGIN_LANGUAGE")
public class AuthorityTextView extends EntityCommons implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "AUTHORITYID", length = 36)
private String authorityId;
#Id
#Column(name = "LANG", length = 2)
private String lang;
#Column(name = "AUTHORITYTEXT", length = 255)
private String authorityText;
#Column(name = "DEFAULTUSED")
private Boolean defaultUsed;
public String getAuthorityId() {
return authorityId;
}
public String getLang() {
return lang;
}
public String getAuthorityText() {
return this.authorityText;
}
public Boolean getDefaultUsed() {
return this.defaultUsed;
}
}
My Query Redirector is listed below
public class VPMQueryRedirector implements QueryRedirector {
private static final long serialVersionUID = 3912645701055442481L;
private Logger logger = LoggerFactory.getLogger(getClass());
#Override
public Object invokeQuery(DatabaseQuery query, Record arguments, Session session) {
query.setDoNotRedirect(true);
String translatedSQLString = query.getTranslatedSQLString(session, arguments);
}
I have create a bug under eclipselink, but there hasn't been any updates yet if the observation is correct or not.

Spring JPA query using specification and projection

I used spring jpa specification to build dynamically an entity query.
It's working perfect but the query returns all entity fields which makes the performance slower.
I want to fetch specific entity fields only and not fetching all entity fields and dependencies which I don't want and I will not use.
I search on the web, I tried some scenarios but without any lack.
Can anyone suggest any solution on this?
Thanks in advance
Here is what I have.I'm using spring boot 2.2.4
public class Concert {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String name;
#Column
private String code;
#Column
private double totalIncome;
#Column
private double totalExpenses;
#Column
private double totalBudget;
#ManyToOne(targetEntity = Orchestra.class, fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "orchestra_id")
private Orchestra orchestra;
#ManyToOne(targetEntity = ConcertStatus.class, fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "concert_status_id")
private ConcertStatus status;
/* other fields */
}
Specification:
public class ConcertSpecification implements Specification<Concert> {
#Override
public Predicate toPredicate(Root<Concert> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
List<Predicate> predicates = new ArrayList<>();
//add add criteria to predicates
for (Criterion criteria : criteriaList) {
/* predicates builder here */
}
return builder.and(predicates.toArray(new Predicate[0]));
}
}
Repository:
public interface ConcertDao extends JpaRepository<Concert, Long>, JpaSpecificationExecutor<Concert>, PagingAndSortingRepository<Concert, Long> { }
ConcertService:
public interface ConcertService {
Page<Concert> findAll(#Nullable Specification<Concert> spec, Pageable pageable);
}
ConcertServiceImpl:
#Service(value = "concertService")
public class ConcertServiceImpl implements ConcertService {
public Page<Concert> findAll(#Nullable Specification<Concert> spec, Pageable pageable){
List<Concert> list = new ArrayList<>();
concertDao.findAll(spec).iterator().forEachRemaining(list::add);
return new PageImpl<Concert>(list);
}
}
Usage of projections with specifications are not supported and there is a PR for it that has been hanging for over five years.

Return more data than model contains using Spring Data

I'm working with Spring Data which is great stuff, but sometimes I need to get more data from database than my model can handle. For example I have model like below.
#Entity
#Table(name = "email")
public class Mail implements Serializable {
#Getter
#Setter
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private Long id;
#Getter
#Setter
private String text;
}
An I my query will be more complex than usual. I want to get my model and in addition number of similar entities, using group by.
#Query(value = "SELECT m, COUNT(m) as countValue FROM Mail m GROUP BY m.text")
List<Mail> findAllNewsletters();
How I should handle something like that? My model does't contain countValue so I will get List<Object[]>
How to deal with that situation, keep my code clean, easiness
of using this.
Step 1: Create a container class to hold the output from your query.
class MailOccurence {
private final Mail mail;
private final Long recurrence;
public MailOccurence(final Mail mail, final Long recurrence) {
this.mail = mail;
this.recurrence = recurrence;
}
public Mail getMail() { return mail; }
public Long getRecurrence() { return recurrence; }
}
Step 2: Populate and return instances of the container class from the query.
Query(value = "SELECT new MailOccurence(m, COUNT(m)) FROM Mail m GROUP BY m.text")
List<MailGroup> findAllNewsletters();
For full details, see the JPA specification.
You can go for a DTO like following
public class MailEntry {
private Long id;
private String text;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
and inside your business logic you can take the advantage of spring template something like following
#Autowired
JdbcTemplate jdbcTemplate;
private static final String SQL = "SELECT m, COUNT(m) as countValue FROM Mail m GROUP BY m.text";
public List<MailEntry> getMailEntries() {
List<MailEntry> mailEntryList = jdbcTemplate.query(SQL, new RowMapper<MailEntry>() {
public MailEntry mapRow(ResultSet rs, int rowNum) throws SQLException {
MailEntry mailEntry = new MailEntry();
mailEntry.setId(rs.getInt(1));
mailEntry.setText(rs.getString(2));
return mailEntry;
}
});
return mailEntryList;
}
Hope this help.

JPA Mapping embedded fields with createNativeQuery

I have an entity with has a field which represents composite primary key annotated with embeddeid and another field which is annotated with embedded annotation.
Both of these fields are not directly mapped with the the columns returned by the query passed to createNativeQuery method.
The getResultList returns me the list of entities, but the two fields which I mentioned are null in all the entities.
public interface Key{
public int hashCode()
}
#Embeddable
public class CompositePK impements Key{
private int empid;
private Date startdate;
private Date enddate;
}
#Embeddable
public class PartitionKey implements Key{
private String empname;
}
#Entity
public class Employee {
#EmbeddedId
private CompositePK id;
#Embedded
private PartitionKey name;
#Column(name="empid")
private int empid;
#Column(name="empname")
private String empname;
#Column(name="startdate")
private Date startdate;
#Column(name="enddate")
private Date enddate;
}
public class Loader{
private static EntityManager em;
public static void main(String [] args){
//code to instantiate em goes here
//...
//....
Query query = em.createNativeQuery("select empid,empname,startdate,enddate from employees", Employee.class );
List entities = query.getResultList();
//print the list
System.out.println(entities);
}
}
The outcome of this is that the entities are populated but their fieldsid and name which are emdedded fields are null. Can anyone please suggest how to populate these two fields?
Thanks

Using Pageable to query a collection

I have two entities. A NewsCategory and a NewsItem which have a one-to-many relationship.
NewsCategory
#Entity
public class NewsCategory extends AbstractEntity<Long> {
private String name;
#OneToMany(cascade = CascadeType.ALL)
private List<NewsItem> items = new ArrayList<>();
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public List<NewsItem> getItems() {
return items;
}
}
NewsItem
#Entity
public class NewsItem extends AbstractEntity<Long> {
private String title;
private LocalDate startDate;
private LocalDate endDate;
private String resource;
#Column(columnDefinition = "text")
private String content;
// getters and setters...
}
Repository interface
I would like to have the items collection to be pageable but I'm having some difficulties with defining the repository interface for it.
This interface does not work like expected.
public interface NewsCategoryRepository extends JpaRepository<NewsCategory, Long> {
#Query("SELECT e.items FROM #{#entityName} e WHERE e = ?1")
public List<NewsItem> findItems(NewsCategory category, Pageable pageable);
}
When executing findItems() the following exception is thrown.
Caused by: org.hibernate.QueryException: illegal attempt to dereference collection [newscatego0_.id.items] with element property reference [startDate] [SELECT e.items FROM NewsCategory e WHERE e = ?1 order by e.items.startDate asc]
How can I modify the above interface so it will return a portion of the items property using Spring Data and Pageable?