SpringData - Get single column querying by method's name - java

I created a method which through spring data automatically create the query. The problem is about the return param, because dismatch from the name definition.
In fact by specifying only one parameter, it return 4 parameters.
The springData method is that:
Optional<Comunicazioni> getCommIDByExtIDAndCommSAndCommT(
BigDecimal extID, String commS, String commT);
and I access to the type like so:
getCommIDByExtIDAndCommSAndCommT(extId, commS, commT).get().getCommID()
how can I retrieve only the column I need?
Thank you

Unfortunately, this is not possible with the current implementation of Spring Data JPA (i.e. Using method name only).
Instead, the current solution is to use #Query to define the return values. You can find an example of that here.
However, if your Entity object is not too large, you would be able to achieve the result in the example you posted by simply retrieving the entire entity:
Optional<Comunicazioni> findByExtIDAndCommSAndCommT(BigDecimal extID, String commS, String commT);
and then calling it as
repo.findByExtIDAndCommSAndCommT(extId, commS, commT).get().getCommID();
It would be nice to see this functionality in the future, but for now, it is not so difficult to work around.

Related

Can I add condition with spring data standard interface methods

Can I add condition to provided interface method like "findAll" of spring data? For example, if the table has columns "name" and "deleted" - I can create a query asfindByNameAndDeletedIsNull which will give all names which have not been deleted. I tried "findAllAndDeletedIsNull" but this does not work - is this possible?
I know it can be achieved with #query, but was curios as how can we augment the standard methods with conditions.
You can do "findByDeletedIsNull"
See here for more info on what key words can be used in a method name.
According to the documentation, there's a specific way to name the method to have it parsed into the correct SQL. Look at this section: Spring Data JPA reference - query.
If you have the query ready, you can easily reverse-engineer which method name may help you get the same result. You can compose quite complex queries by building up from those foundation bricks. However, you cannot just create a string representation of the "where" clause as a named method.
From the document, if you want to get all records where a field is null:
IsNull | findByAgeIsNull | … where x.age is null
will mean a method name such as findByDeletedIsNull.

Spring Data MongoDB template converts to wrong class

Using Spring 5.0.6 and Spring-Data-Mongo 2.0.7, I have an issue when fetching entities being transformed into the wrong class. See the following simplified scenario:
Entity setup:
public class PersistableObject {
#Id #Field("_id") private String id;
}
#Document(collection = "myapp_user")
public class User extends PersistableObject {...}
public class RealUser extends User {...}
public class VirtualUser extends User {...}
So, there is a common MongoDB collection storing both types of User, discriminated by the automatically added _class property.
Furthermore, there is a Repository into which the MongoTemplate is injected.
#Autowired
private org.springframework.data.mongodb.core.MongoTemplate template;
Everything fine, so far. Now, if I want to fetch all documents that contain a RealUser, I could call this
template.findAll(RealUser.class)
I'd expect the template to find all documents that have the discriminator property _class set to com.myapp.domain.RealUser.
But this doesn't work as expected. I even get all VirtualUsers, as well, put into objects of type RealUser with all VirtualUser-specific properties missing, and all RealUser-specific properties set to null.
Furthermore, when I go and save a User, which is actually a VirtualUser in MongoDB, but has been squeezed into a RealUser class, Spring would change the _class-property to the wrong type, magically converting a VirtualUser into a RealUser.
So both methods here would load the entire collection and squeeze all objects into the specified class, even if it is the wrong one:
template.findAll(VirtualUser.class)
template.findAll(RealUser.class)
This behavior is probably not desired, or if so, then it is extremely misleading and harmful. You can easily shred your whole data with this.
Can anyone shed some light on this?
I've created a ticket at Spring's Jira. Find Olivers comment below:
The method actually works as expected but I agree that we need to
improve the JavaDoc. The method is basically specified as "Load the
documents the given type is configured to persisted in and map all of
them (hence the name) to the given type". The type given to it is not
used as a type mapping criteria at the same time. Every restriction
you want to apply on the documents returned needs to be applied
through a Query instance, which exposes a ….restrict(…) method that
allows to only select documents that carry type information.
The reason that findAll works the way it works is that generally
speaking – i.e. without an inheritance scenario in place – we need to
be able to read all documents, even if they don't carry any type
information. Assume a collection with documents representing people
that have not been written using Spring Data. If a
findAll(Person.class) applied type restrictions, the call would return
no documents even if there were documents present. Unfortunately we
don't know if the collection about to be queried carries type
information. In fact, some documents might carry type information,
some might not. The only way to reasonably control this, is to let the
user decide, which she can by either calling Query.restrict(…) or not.
The former selects documents with type information only, the latter.
As I said, I totally see that the JavaDoc might be misleading here.
I'm gonna use this ticket to improve on that. Would love to hear if
the usage of Query.restict(…) allows you to achieve what you want.

underlying procedure for someMethod(SomeClass.class)

in hibernate to create criteria we use
Criteria criterea=session.createCritera(SomeClass.class)
It may be available in some other examples too but I am not able to understand the structure of these type of methods.
NOTE this is an example I am trying to put to understand use of SomeClass.class like arguments
my question here is what is purpose of SomeClass.class ? why do we need it, what is the advantages of using it as argument.
Edit its not a duplicate but have string connection to this question
What is this .class syntax?
If you attach .class to the end of a class name, you get the Class<T> object corresponding to the class.
Examples:
String.class returns an instance of Class<String>
Integer.class returns an instance of Class<Integer>
What can you do with a class object
Reflection! If you have access to a class object, you can do all kinds of cool stuff! You can call methods, get and set values of fields...
Why is this used in Hibernate?
I haven't used hibernate before, but this syntax is used in other libraries as well, especially in ORMs or JSON serializers. I'll use JSON serializers as an example as I'm more familiar with those.
In a JSON serializer, you need to give it a class object because it needs to get all the fields that you want to serialize to JSON. It uses reflection to get and set the values of those fields, then convert them to JSON. When it deserializes JSON, it finds the field that needs to be set with the name in the JSON. These operations require a Class object because without it, how can Java know which class should it find the field? Also, to create a new object with reflection, a Class is needed as well!
Hibernate provides many ways to handle the objects in relation with RDBMS tables.
One way is Session interface providing createCriteria() method which can be used to create a Criteria object.
As name says criteria, it is useful to execute queries by applying filtration rules and logical conditions of programmer wish.
For example:
Criteria obj=session.createCritera(Galaxy.class) // say SomeClass is Galaxy.class
List results = obj.list();
Here, criteria query is one which will simply return every object that corresponds to the Galaxy class.
We even can restrict the results with criteria, example add() method available for Criteria object to add restriction for a criteria query.
Following is the restriction to return the records with planet which has 7.4 billion population from Galaxy class:
Criteria cr = session.createCriteria(Galaxy.class);
cr.add(Restrictions.eq(“planet”, 75000000000));
List results = cr.list();

what is session.selectOne(String arg0, Objectarg1);?

i am new to MyBatis,i am unable to find tutorials to learn,present i am going to start working on MyBatis with Spring,i had used session.selectOne(String arg0, Object arg1) but i am not able to understand how it works and what it will do with the second parameter that is Object arg1.
can any one help in this.
thank you
The second argument to selectOne and selectList is for a parameter. It can be a primitive if you have very simple needs in your query, say a single integer, or for more complicated queries requiring many values to be interpolated, a bean class instance with the values populated as needed (and containing the proper getters and setters).
In your mapper file you then define the type of the parameter via the parameter attribute, and can then interpolate either inline or with escaping (the former for things that should never be escaped, such as variable table or column names, and the latter for things which should always be escaped, such as values in a WHERE clause).
See the MyBatis doc for more detail:
http://mybatis.github.io/mybatis-3/java-api.html
Response to comments from OP:
MapBuilder must be custom code related to Map data structures. There's an ImmutableMap.Builder as part of Guava, but that doesn't seem like what this is. I don't think it's related to Mybatis per se.
It looks like that code is just building up a Map object, and then passing it off to the selectOne query for use within the query definition in the mapper (instead of a custom bean class).
What's the definition on LoginMapper.getUserByUsername in your mapper? In that definition, the contents of the map object are likely being interpolated into the query so dynamic values can be included.

How to create case-insensitive field on Java POJO. Looking for a good design.

So I'm using GigaSpaces XAP with Hibernate plugin to load my DB table into the their grid cache, unfortunately for querying the grid they do not support directly case insensitive searches.
They offered 2 solutions:
1- Use LIKE query (same as SQL) which is slow (Wont even bother with this)
2- Create a separate property of the fields I want to have case insensitive.
So now my choices are:
1- Create an extra column in DB to have case-insensitive field (Not in this life time)
2- Create a custom data loader plugin for XAP such that the moment the data is loaded the field is stored in a "ToLower" properperty. (Supported but will leave as last resort)
I'm definitely not going with #1 and I will leave the custom data loader as a last result. So my idea is to...
class Person {
String firstName
String firstNameLower
public void setFirstName(String firstName) {
this.firstName = firstName
this.firstNameLower = firstName.toLowerCase(...);
}
}
Will this work with Hibernate? As the GigaSpace dataloader uses Hibernate and my pojo is pretty much an Entity class. I'm using Hibernate XML mapping not annotations. The "ToLower" fields will not be mapped. Does Hibernate call setXXX() on all fields that are mapped or does it do some fancy code replacement under the hood and doesn't call the setXXX() methods.
I'm also thinking an annotation would be good use here but not sure how to implement them or even if it's possible for this case.
hibernate does use proxy objects, but the data is still stored in your object and hibernate will use the getter/setter implementations you provide, so your solution should work if you want to set the lowercase version, although I'm not clear why you need a separate instance variable to store the lowercase version.
this article goes over the basics of proxies.
For anyone interested.
Simply create a "tolower()" method of the field and add the index annotation on that and you can map your pojo to hibernate the usual way.
If you configure Hibernate to use the fields accessor method (and not directly access the fields) its default behavior is to use all the setXXX() method.
I think in your case the best solution would be (if Hibernate is only used for GigaSpace) to customise the way Hibernate load the data, by defining a custom type using standrd StringType to load the data then converting it to lower case...
Meanwhile, if your system requires lower case data, can't you make sure all strings entered into the database are lower case ?

Categories