I have a spring application that should connect to an existing database and just query an entity for existence based on some attributes.
I don't want to create a #Entity class for this. But I still want to use the spring managed EntityManager etc.
When using Spring, what is the best approach to just query a select for that entity? Using em.createNamedQuery(QUERY); with String QUERY = "SELECT count(*) from my_table where username =: username AND email := email)";?
Answers from #predrag-maric and #pL4Gu33 are both correct but if you use JPA in your project (for example, Hibernate) you might consider using #NamedNativeQuery annotation as well.
More about named native queries.
simple example of native query
#PersistenceContext
EntityManager em;
public String test(Integer id)
{
Query query = em.createNativeQuery("SELECT name FROM Accounts where id=?");
query.setParameter(1,id);
return query.getSingleResult();
}
You can use this method from entitymanager. http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#createNativeQuery%28java.lang.String%29
Use em.createNativeQuery(QUERY). Also, you'll have to use positional parameters (?1) instead of named parameters (:email), because only positional parameters are supported by JPA in native queries.
Related
I have a list of entities in my code (google.com, amazon.com, etc), and I would like to have my repository find an entity when I type feed it a string with a subdomain.
So basically, what repository function do I implement so I can run something like
public List<ValidDomainsEntity> findByCompanyDomainLike("www.google.com");
and have it return the entity with google.com in its
String companyDomain;
where the companyDomain = "google.com"
So in more layman's terms: My db contains URL's without the subdomain or prefix. What query do I use in spring's repository to find that URL when I put in a URL with a subdomain
Edit: Basically how I do the spring equivalent of
select * from valid_domains where 'www.amazon.com' LIKE CONCAT('%', companyDomain);
You can write it in several ways. First option is writing a native query.
#Query(value = "select * from valid_domains where 'www.amazon.com' LIKE CONCAT('%', :companyDomain", nativeQuery = true);
public List<ValidDomainsEntity> myQuery(#Param("companyDomain") String companyDomain);
Second option is writing a simple non native Query and use your Entiry class names and fields. For this you purpose you can use javax.persistence.EntityManager or #Query(value = "", nativeQuery = false). By default #Query is non native query, you dont have to write nativeQuery = true. I show also an EntityManager example.
#Autowired //Constructor dependency injection is more preferred instead of #Autowired
private EntityManager entityManager;
List<ValidDomain> query = entityManager.createQuery("SELECT new ValidDomain(d.id, d.domainName) from ValidDomain d where 'www.amazon.com' LIKE CONCAT('%', :variableName)", ValidDomain.class).getResultList();
Or you can also use EntityManager, entityManager.createNativeQuery() for creating native query.
I am using below jpa code. How can we prevent below code from sql injections?
List<Document> docs= em.createQuery("SELECT c FROM Document c WHERE c.docId = :docId ", Document.class)
.setParameter("docId", docId).getResultList();
http://www.adam-bien.com/roller/abien/entry/preventing_injection_in_jpa_query
It already is protected against SQL injection. Your code is using parameters.
Also if you want, you can use Criteria APIs to build the same query.
#Query(value = "SELECT * FROM H4 WHERE 1")
List getResult();
Instead of the query "SELECT * FROM H4 WHERE 1" I want to put a String variable containing query generated elsewhere.
#Query, like any other annotation, uses a compile time constant to define attributes. You can't define it's value in runtime unless you plan to hack the Spring Data JPA framework.
You should use either Specifications with criteria, Query by example or JPQL to define and execute your dynamic query.
Create constants and set the value as below.
#Query(value = ApplicationConstantClass.QUERY_STRING_CONSTANT)
List getResult();
or Use EntityManager or SessionFactory of hibernate to execute dynamically generated query.
I have a named query as below;
#NamedQuery(name = "MyEntityClass.findSomething", query = "SELECT item FROM MyTable mytbl")
Now I want to append dynamic sort clause to this query (based on UI parameters)
Can I get an example using JPQL for doing the same (like how to set a dynamic ORDER BY in the Entity class)
I have already tried using CriteriaQuery, but was looking for a JPQL implementation now.
NamedQueries are by definition NOT dynamic, it is not correct to change them programmatically.
So the way to go is to create a JPQL query (but not a named query) like this:
TypedQuery<MyEntity> query = em.createdQuery("SELECT item FROM MyEntity item ORDER BY "+sortingCol, MyEntity.class);
On the other hand, if you REALLY want to use the named query, you could do that the following way:
#NamedQuery(name = "MyEntityClass.findSomething", query = MyEntity.NAMED_QUERY)
#Entity
public class MyEntity {
public static final NAMED_QUERY= "SELECT item FROM MyTable mytbl";
//+your persistent fields/properties...
}
//and later in your code
TypedQuery<MyEntity> query = entityManager.createQuery(MyEntity.NAMED_QUERY + " ORDER BY " + sortingCol, MyEntity.class);
Complementing for JPA 2.1
As of JPA 2.1 it is possible to define named queries programmatically.
This can be achieved using entityManagerFactory.addNamedQuery(String name, Query).
Example:
Query q = this.em.createQuery("SELECT a FROM Book b JOIN b.authors a WHERE b.title LIKE :title GROUP BY a");
this.em.getEntityManagerFactory().addNamedQuery("selectAuthorOfBook", q);
// then use like any namedQuery
Reference here
This can be useful, for instance, if you have the orderby field defined as a application parameter. So, when the application starts up or on the first run of the query, you could define the NamedQuery with the defined OrderBy field.
On the other side, if your OrderBy can be changed anytime (or changes a lot), then you need dynamic queries instead of NamedQuery (static). It would not worth to (re)create a NamedQuery every time (by performance).
#NamedQuery
Persistence Provider converts the named queries from JPQL to SQL at deployment time.
Until now, there is no feature to create/update the query with #NamedQuery annotation at runtime.
On the other hand, you can use Reflection API, to change the annotation value at runtime. I think It is not solution, also it is not you wanted .
em.createQuery()
Persistence Provider converts the dynamic queries from JPQL to SQL every time it is invoked.
The main advantage of using dynamic queries is that the query can be created based on the user inputs.
In Mysql,
SELECT id FROM table ORDER BY RANDOM() LIMIT 5
this sql can select 5 random rows. How to do this via JPA Query (Hibernate as provider, Mysql database)?
Thanks.
Only the functions defined in the specification are guaranteed to be supported by all JPA providers and RAND or RANDOM aren't. So I don't think that you can do it in JPQL.
However, it would be possible in HQL (the order by clause in HQL is passed through to the database, so you can use any function):
String query = "SELECT o.id FROM Order o ORDER BY random()";
Query q = em.createQuery(query);
q.setMaxResults(5);
But, I repeat:
This may not work with another database.
This may not work with another JPA provider.
Try calculating the random beforehand and construct your JPQL/HQL/native query with the pre-calculated random value.
I just Achieved this by a simple way, This may not seem lot of cute but it will do the purpose. this solution is for Java 8 or above only, I m using spring boot.
First I have the following service call that will provide an EntityManager to my default Repository interface method, The autowiring is a singleton so I believe that this stays performance freindly.
#PersistenceContext
private EntityManager entityManager;
#Override
public UserResp getRandomUser() {
long orderByRandom = (long) ((java.lang.Math.random()*100 % 10 )+1);
return userMapper.entityToModel(userRepository.pickRandomUser(orderByRandom,entityManager));
}
Then my repository looks like
#Transactional
default User pickRandomUser(Long rand, EntityManager manager) {
return manager.createQuery("SELECT u FROM User u ORDER BY "+rand,User.class).setMaxResults(1).getSingleResult();
}