Use WHERE in JPA to query the entity - java

I have this entity:
#Entity
#Table
public class Terminals implements Serializable {
private static final long serialVersionUID = 5288308199642977991L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
#Column
private int merchant_id;
#Column
private String terminalToken;
.....
}
I tried to use this query:
public Terminals getTerminalToken(String terminalToken) throws Exception {
return entityManager.find(Terminals.class, terminalToken);
}
Looks like it's selecting only the table key.
How I can select the table column terminalToken?

You better use Spring data to build your queries along with JPA Repositories. You will just need to extend the JpaRepository interface, and follow the naming conventions to name your methods.
Your method will look like this:
public List<Terminal> findByTeminalToken(String TerminalToken);
Otherwise you will need to use entityManager.createQuery() method instead of entityManager.find() because the latter one is only used with the id column.

If you are looking for pure java (i am more in favour of Philipp solution) perhaps you wish to check out this solution. https://www.objectdb.com/java/jpa/query/criteria. Sorry for not posting a direct solution but i think it woths more to give you the source.
By the way, why not using spring data? Much easier

Related

Spring Data JPA Query By Example with related entities

I seem to be unable to add QueryByExample probes that match related entities.
#Entity
#Data
public class ArtistEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
#ManyToMany(fetch = FetchType.EAGER)
private Set<GenreEntity> genreList = new HashSet<>();
#Version
private Long version;
}
#Entity
#Data
public class GenreEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#Version
private Long version;
}
#Repository
public interface ArtistRepository extends JpaRepository<ArtistEntity, Long> {
}
When I try the following query, according to Hibernate's logs, my probe isn't running any conditions against the Genre
GenreEntity genreEntity = new GenreEntity();
genreEntity.setName("Heavy Metal");
ArtistEntity artistEntity = new ArtistEntity();
Set<GenreEntity> genreEntitySet = new HashSet<>();
genreEntitySet.add(genreEntity);
artistEntity.setGenreList(genreEntitySet);
Example<ArtistEntity> example = Example.of(artistEntity);
Pageable pagination = PageRequest.of(0, 10);
artistRepository.findAll(example, pagination);
I also tried looking on the Spring Data JPA documentation regarding QBE, but I didn't find anything specifically mentioning this limitation, which brought me to assume it's an unexpected behaviour.
Currently, you cannot do this with Query By Example.
The spring document states that this only works with SingularAttribute.
Currently, only SingularAttribute properties can be used for property
matching. https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#query-by-example.running
You want to search by a property that is a Set<GenreEntity> (genreList), which is a PluralAttribute. It is not possible to search by this field.
It will be ignored when building a query, as can be seen here: https://github.com/spring-projects/spring-data-jpa/blob/master/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java#L127
You can use Specification.
Advanced Spring Data JPA - Specifications and Querydsl. https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
For this you need to extend from interface JpaSpecificationExecutor:
public interface ArtistRepository extends JpaRepository<ArtistEntity>, JpaSpecificationExecutor<ArtistEntity> {
}
And you also need to implement your custom Specification<T>.
And then you can use findAll(Specification<T> spec, Pageable pageable).
You may just use this library which supports nested fields and much more: https://github.com/turkraft/spring-filter
It will let you run search queries such as:
/search?filter= average(ratings) > 4.5 and brand.name in ('audi', 'land rover') and (year > 2018 or km < 50000) and color : 'white' and accidents is empty

JPA: Ignore field on Fetch, but save all while saving it. Is there any annotation attribute to do so?

I have the following Entity. In this I want to fetch all data except phoneNumber. What will be the best solution? It would be fine if I could do it with annotation.
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "employee_name")
private String name;
#Column(name = "gender")
private char gender;
#Column(name = "date_of_birth")
private String dob;
#Column(name = "skills")
private String[] skills;
#Column(name = "phone_number")
private String phoneNumber;
//getter setter
}
To tell what will be the best way to do this you have to say why you want to do this and what you want to achieve.
There are many options:
omit the getter
use a projection (DTO or interface)
use inhreitance
use inheritance with #MappedSuperclass
Can you please use #Transient on your field. If it is a subclass of anyclass then on class level please use #Embedded.
If not then you need to read this as this is always lazy fetch From Hibernate, Chapter 19. Improving performance:
Lazy attribute fetching: an attribute or single valued association is fetched when the instance variable is accessed. This approach requires buildtime bytecode instrumentation and is rarely necessary.
You can use #Column(insertable = true, updatable = false) and I am not sure if we can ignore while fetching using entity. you can achieve your requirements using JPA Projections
Also,#JsonIgnore may be useful. it is used to tell Jackson to ignore a certain property of a Java object but

Crnk JsonApiRelation, OneToMany and filtering implementation

I use crnk (JSON-API) in java project and I have 3 questions regarding its usage with spring boot and jpa - haven't found exact implementation details in documentation.
For example, I have 2 entities and respective tables:
#Entity
#JsonApiResource(type = "employee")
public class Employee {
#Id
#JsonApiId
private int id;
private String name;
#ManyToOne
#JoinColumn(name = "typeId")
private EmployeeType employeeType; //stored in table as typeId
}
#Entity
#JsonApiResource(type = "type")
public class EmployeeType {
#Id
#JsonApiId
private int id;
private String typeName;
private int salary;
}
How should JsonApiRelation be introduced in order to be able to call "/employee/1" and "/employee/1/type" urls?
For example there is one more entity.
#Entity
#JsonApiResource(type = "project")
public class Project {
#Id
#JsonApiId
private int id;
private String supervisorName;
private String projectName;
}
First, I'd like to have List of Projects for each Employee, where he is a supervisor, joint by name and have it listed as attribute in Json.
Tried implementing it with #OneToMany and #JoinColumn annotations but got StackOverflowException. How could this be implemented. And second, how could this be implemented with Relation? Like "/employee/1/projects" url.
How should I implement custom filtering of results for findAll method? For example, I have a List of all Employees, but I'd like to exclude some of them from the response. Which class/method should be introduced for this behaviour?
#JsonApiRelation annotation should not be necessary. Crnk will detect the #ManyToOne annotation and map it accordingly.
in case of crnk-jpa it is sufficient to specify all relationships in JPA. Matching JSON API relationships. So your approach seems good. What was the StackoverflowException stacktrace? (next to the examples, there are also many example entities in crnk-jpa)
I would make use of a decorator. See http://www.crnk.io/documentation/#_request_filtering. RepositoryDecoratorFactory allows to place a custom repository between the caller and crnk-jpa (or any other kind of repository). There you can do any kind of modification perform (maybe) calling the "real" repository. => Will add an example for this
feel free also make open up tickets in crnk for any documentation/example clarifications.

Hibernate and #JoinFormula: org.hibernate.mapping.Formula cannot be cast to org.hibernate.mapping.Column

I'm trying to write a hibernate adapter for an old database schema. This schema does not have a dedicated id column, but uses about three other columns to join data.
On some tables, I need to use coalesce. This is what I came up with so far:
About the definition:
A car can have elements, assigned by the car's user or by the car's group of users.
If FORIGN_ELEMENT holds a user's name, definition will be 'u'
If FORIGN_ELEMENT holds a group's name, definition will be 'g'
This also means, one table (CAR_TO_ELEMENT) is misused to map cars to elements and cargroups to elements. I defined a superclass CarElement and subclasses CarUserElement and CarGroupElement.
state is either "active" or an uninteresting string
I set definitition and state elsewhere, we do not need to worry about this.
Use DEP_NR on the join table. If it's zero, use USR_DEP_NR. I did this with COALESCE(NULLIF()) successfully in native SQL and want to achieve the same in Hibernate with Pojos.
Okay, here we go with the code:
#Entity
#Table(name="CAR")
public class Car extends TableEntry implements Serializable {
#Id
#Column(name="DEP_NR")
private int depnr;
#Id
#Column(name="USER_NAME")
#Type(type="TrimmedString")
private String username;
#ManyToOne(fetch = FetchType.EAGER, targetEntity=CarGroup.class)
#JoinColumns(value={
#JoinColumn(name="GROUP_NAME"),
#JoinColumn(name="DEP_NR"),
#JoinColumn(name="state"),
})
private CarGroup group;
#OneToMany(fetch=FetchType.EAGER, targetEntity=CarUserElement.class, mappedBy="car")
private Set<CarUserElement> elements;
}
#Entity
#Table(name="CAR_GROUP")
public class CarGroup extends TableEntry implements Serializable {
#Id
#Column(name="DEP_NR")
private int depnr;
#Id
#Column(name="GROUP_NAME")
#Type(type="TrimmedString")
private String group;
#ManyToOne(fetch = FetchType.EAGER, targetEntity=Car.class)
#JoinColumns(value={
#JoinColumn(name="GROUP_NAME"),
#JoinColumn(name="DEP_NR"),
#JoinColumn(name="state"),
})
private Set<Car> cars;
#OneToMany(fetch=FetchType.EAGER, targetEntity=CarGroupElement.class, mappedBy="car")
private Set<CarGroupElement> elements;
}
#MappedSuperclass
public class CarElement extends TableEntry {
#Id
#ManyToOne(fetch = FetchType.EAGER, targetEntity=Element.class)
#JoinColumns(value={
#JoinColumn(name="ELEMENT_NAME"),
#JoinColumn(name="state"),
})
private Element element;
}
#Entity
#Table(name="CAR_TO_ELEMENT")
public class CarUserElement extends CarElement {
#Id
#Column(name="DEFINITION")
private char definition;
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumnsOrFormulas(value = {
#JoinColumnOrFormula(formula=#JoinFormula(value="COALESCE(NULLIF(DEP_NR, 0), USR_DEP_NR)", referencedColumnName="DEP_NR")),
#JoinColumnOrFormula(column=#JoinColumn(name="FORIGN_ELEMENT", referencedColumnName="USER_NAME")),
#JoinColumnOrFormula(column=#JoinColumn(name="STATE", referencedColumnName="STATE"))
})
private Car car;
}
#Entity
#Table(name="CAR_TO_ELEMENT")
public class CarGroupElement extends CarElement {
#Id
#Column(name="DEFINITION")
private char definition;
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumnsOrFormulas(value = {
#JoinColumnOrFormula(formula=#JoinFormula(value="COALESCE(NULLIF(DEP_NR, 0), USR_DEP_NR)", referencedColumnName="DEP_NR")),
#JoinColumnOrFormula(column=#JoinColumn(name="FORIGN_ELEMENT", referencedColumnName="GROUP_NAME")),
#JoinColumnOrFormula(column=#JoinColumn(name="STATE", referencedColumnName="STATE"))
})
private Car car;
}
I tried all available versions of hibernate (from 3.5.1 [first version with #JoinColumnsOrFormulas] up to 4.x.x), but I always get this error:
Exception in thread "main" java.lang.ClassCastException: org.hibernate.mapping.Formula cannot be cast to org.hibernate.mapping.Column
at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:351)
at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1338)
at org.hibernate.cfg.annotations.CollectionBinder.bindOneToManySecondPass(CollectionBinder.java:791)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:719)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:668)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:66)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1597)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1355)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1737)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1788)
Other hibernate users seem to have the same problem: They can't get it working with any version, see this thread and other stackoverflow questions:
https://forum.hibernate.org/viewtopic.php?f=1&t=1010559
To be more complete, here's my TrimmedString Class:
https://forum.hibernate.org/viewtopic.php?p=2191674&sid=049b85950db50a8bd145f9dac49a5f6e#p2191674
Thanks in advance!
PS: It works with joining just these three colulmns with just one DEP-NR-Column (i.e. either DEP_NR OR USR_DEP_NR using just #JoinColumns). But I need this coalesce(nullif()).
I ran into a similar problem, and it seems that the issue is that you are using a #Formula inside an #Id. Hibernate wants Ids to be insertable, and Formulas are read-only.
In my case I was able to work around the problem by making the individual columns Id properties on their own, and making the joined object a separate property. I don't know if this would work in your case since you're using two different columns in your formula, but if so your code might look something like:
#Entity
#Table(name="CAR_TO_ELEMENT")
public class CarUserElement extends CarElement {
#Id
#Column(name="DEFINITION")
private char definition;
#Id
#Column(name="DEP_NR")
private Integer depNr;
#Id
#Column(name="USR_DEP_NR")
private Integer usrDepNr;
#Id
#Column(name="FORIGN_ELEMENT")
private String userName;
#Id
#Column(name="STATE")
private String state;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumnsOrFormulas(value = {
#JoinColumnOrFormula(formula=#JoinFormula(value="COALESCE(NULLIF(DEP_NR, 0), USR_DEP_NR)", referencedColumnName="DEP_NR")),
#JoinColumnOrFormula(column=#JoinColumn(name="FORIGN_ELEMENT", referencedColumnName="USER_NAME", insertable = false, updatable = false)),
#JoinColumnOrFormula(column=#JoinColumn(name="STATE", referencedColumnName="STATE", insertable = false, updatable = false))
})
private Car car;
}
Join formulas are very fragile in Hibernate for the time being; I always had a difficult time to get them work properly.
The workaround that helped me often was to create database views which exposed the proper columns (including foreign keys that don't exist in the original tables). Then I mapped the entities to the views using classing Hibernate/JPA mappings.
Sometimes there are redundant joins in the generated SQL when using such entities, but the database optimizes such queries in most cases so that the execution plan is optimal anyway.
Another approach could be using #Subselects, which are some kind of Hibernate views, but I expect them to be less performant than the classic database views.
I ran into the cast exception as well and I'm on Hibernate 5.x.
Until Hibernate dedicates time to fix the issue, I found that while this guy's approach may not be cleanest (he even eludes to that fact!), it works.
You just need to add the #Column mappings (and get/set methods) to your association table objects that are returning null and manually set the values when you populate the relation data. Simple but effective!

Autoincrement column in oracle using hibernate

I am using hibernate annotations. I want to make a column as autoincremented. I have created a sequence in database(oracle) and mapped that sequence in java POJO class. Do I need to create trigger for that sequence too? I want to know how we can make a column autoincremented while using hibernate anotation? What changes i have to do in java and as well as database side? Please help me in this. Following is the part of code where I have mapped the sequence.
public class SimRuns implements Serializable {
private static final long serialVersionUID = 8698324570356602407L;
#Id #Column(name = "RUN_ID")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_run_id")
#SequenceGenerator(name="seq_run_id", sequenceName="seq_run_id")
private Long runId;
}
This works for me:
#Id
#GeneratedValue(generator = "nosicSeq")
#SequenceGenerator(name = "nosicSeq", sequenceName = "NOSIC_SEQ", allocationSize = 1)
#Column(name = "SID")
private BigDecimal sid;
no triggers in DB needed, just sequence.
Try removing the generator and setting to auto the generationType
#Id #Column(name = "RUN_ID")
#GeneratedValue(strategy=GenerationType.AUTO)
#SequenceGenerator(name="seq_run_id", sequenceName="seq_run_id")
private Long runId;
Hibernate is probably the only JPA Provider that selects the right Generationstrategy based on your databasetype. Using the GenerationType.AUTO statement hibernate will try to select the best strategy to implement an increasing row id.
In Oracle : It's no need for an Oracle trigger, but the sequence is must.
In pojo: you can use Annotations like this:
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="majorsSeq")
#SequenceGenerator(name="majorsSeq", sequenceName="MAJORS_SEQ", allocationSize = 1,initialValue = 1)
public int getId() {
return id;
}

Categories