I want to create a hibernate SQL query and cast it to an object without creating the table.
for example i have
StringBuilder query = new StringBuilder();
query.append("SELECT groupId, categoryId, name FROM AssetCategory");
SQLQuery sqlQuery = session.createSQLQuery(query.toString());
sqlQuery.addEntity("Categories", Categories.class);
List<Categories> list = sqlQuery.list();
The category object is declared like this :
#Entity
public class Categories implements Serializable {
#Column(name = "name")
String name;
#Column(name = "categoryId")
Long categoryId;
#Column(name = "groupId")
Long groupId;
Of course this cant work because there is no ID. And this table does not need to be created either. So how would i go about declaring this ?
Any hints ?
I just cant find the documentation.
you can use a SQLTransformer to do this.. you wont need the annotations in the pojo even.
read this. it will help you realize what you should be doing.
Related
I have an entity TagLabel
it looks like this:
#Entity
#Table(name = "tag_label")
public class TagLabelDB implements Persistable<Long> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long labelId;
#Column(name = "study_instance_UID")
private String stuInsUID;
#Column(name = "tag")
private String tag;
...
I would like to receive a list of distinct tag fields
List tags from JpaRepository
something like:
#Query("SELECT DISTINCT t.tag FROM TagLabelDB t")
List<String> findDistinctTags();
The code above works fine,
but I wouldn't like to use #Query
But Method name, Projection or Specification?...
It looks as a simple question, but I couldn't figure it out...
Distinct keyword can occur in any place of the subject between find (and the other keywords) and by. It means that you can't use distinct like
List<String> findDistinctTagLabelDB();
I want to ask about what is the most efficient way to search about specific data from a database without doing a for loop in all of the records?
I have a project on java spring and I have this Entity:
#Entity
#Table(name = "USERS") public class USERS {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "UID")
private Integer id;
#Column(name = "FName")
private String firstName;
#Column(name = "SName")
private String secondName;
#Column(name = "TName")
private String thirdName;
#Column(name = "LName")
private String fourthName;
#Column(name = "Email")
private String email;
#Column(name = "PW")
private String password;
#Column(name = "MNumber")
private String mobileNumber;
#Column(name = "ISDeleted")
private boolean isUserDeleted;
//---------------------- Getters and Setters ----------------------
and I made this service:
public List<USERS> findAllActive() {
List<USERS> usersList = new ArrayList<USERS>();
for (USERS users: usersRepository.findAll()){
if (!users.isUserDeleted()){
usersList.add(users);
}
}
return usersList;
}
For example; I have one property for User, if he is active or not.
So, my question; what is the most efficient way to do get specific data like retrieving all of the active users from the DB without doing a for loop like in the code above? Because if the list of users is a 1 Million or more, it could have performance issues.
Assuming that you are using JpaRepository then you can create custom query.
#Query("SELECT u FROM USERS u WHERE u.userDeleted = false")
List<USERS> findNotDeletedUsers();
and then call usersRepository.findNotDeletedUsers();
First of all, use an index on the field you want to search on (this won't help you much if the column has only two distinct values, but will make a huge difference if the value has high sparsity).
#Entity
#Table(name = "USERS",
indexes = {
// not a huge performance gain, since the column values are true/false
#Index(name = "index_by_active", columnList="ISDeleted", unique = false),
// possible huge performance gain, since only the relevant records are scanned
#Index(name = "index_by_first_name", columnList="FName", unique = false)})
public class USERS {...}
Then, define a query method that uses the indexed field (if you are using spring data it would look as follows).
public interface UsersRepository extends CrudRepository<USERS, Long> {
List<USERS> findUsersByISDeleted(boolean deleted);
List<USERS> findUsersByFName(String name);
List<USERS> findUsersByFNameAndISDeleted(String name, boolean deleted);
}
Queries on indexed fields will leverage the underlying index and provide an efficient access plan (so you won't end up scanning the whole table in order to extract a subset of entities matching a given criteria).
The solution from #Madis is okay. But if you always want to get users which are not deleted in all queries, you can specify it on Entity:
#Entity
#Table(name = "USERS")
#Where("ISDeleted = false")
public class USERS {
So now the condition "ISDeleted = false" is automatically append to all queries from the UserRepository. You can use usersRepository.findAll() instead of.
You don't need to specify any sql query or where clause. CrudRepository will do it for you automatically. Just use below code and pass true/false on need basis
List<Users> findIsUserDeleted(boolean isDeleted)
I'm using Spring JPA and I need to have a native query. With that query, I need to get only two fields from the table, so I'm trying to use Projections. It isn't working, this is the error I'm getting:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.example.IdsOnly]
I tried to follow precisely the instructions of that page I linked, I tried to make my query non-native (do I actually need it to be native if I use projections, btw?), but I always get that error.
If I use an interface it works, but the results are proxies and I really need them to be "normal results" that I can turn into json.
So, here's my code. The Entity:
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
#Entity
#Table(name = "TestTable")
public class TestTable {
#Id
#Basic(optional = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "Id")
private Integer id;
#Column(name = "OtherId")
private String otherId;
#Column(name = "CreationDate")
#Temporal(TemporalType.TIMESTAMP)
private Date creationDate;
#Column(name = "Type")
private Integer type;
}
The class for the projection:
import lombok.Value;
#Value // This annotation fills in the "hashCode" and "equals" methods, plus the all-arguments constructor
public class IdsOnly {
private final Integer id;
private final String otherId;
}
The Repository:
public interface TestTableRepository extends JpaRepository<TestTable, Integer> {
#Query(value = "select Id, OtherId from TestTable where CreationDate > ?1 and Type in (?2)", nativeQuery = true)
public Collection<IdsOnly> findEntriesAfterDate(Date creationDate, List<Integer> types);
}
And the code that tries to get the data:
#Autowired
TestTableRepository ttRepo;
...
Date theDate = ...
List<Integer> theListOfTypes = ...
...
Collection<IdsOnly> results = ttRepo.findEntriesAfterDate(theDate, theListOfTypes);
Thanks for the help. I really don't understand what I'm doing wrong.
with spring data you can cut the middle-man and simply define
public interface IdsOnly {
Integer getId();
String getOtherId();
}
and use a native query like;
#Query(value = "Id, OtherId from TestTable where CreationDate > ?1 and Type in (?2)", nativeQuery = true)
public Collection<IdsOnly> findEntriesAfterDate(Date creationDate, List<Integer> types);
check out https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
The query should be using a constructor expression:
#Query("select new com.example.IdsOnly(t.id, t.otherId) from TestTable t where t.creationDate > ?1 and t.type in (?2)")
And i dont know Lombok, but make sure there is a constructor that takes the two IDs as parameters.
JPA 2.1 introduces an interesting ConstructorResult feature if you want to keep it native.
You can return list of Object Array (List) as return type of the native query method in repository class.
#Query(
value = "SELECT [type],sum([cost]),[currency] FROM [CostDetails] " +
"where product_id = ? group by [type],[currency] ",
nativeQuery = true
)
public List<Object[]> getCostDetailsByProduct(Long productId);
for(Object[] obj : objectList){
String type = (String) obj[0];
Double cost = (Double) obj[1];
String currency = (String) obj[2];
}
#Query(value = "select isler.saat_dilimi as SAAT, isler.deger as DEGER from isler where isler.id=:id", nativeQuery = true)
List<Period> getById(#Param("id") Long id);
public interface Period{
Long getDEGER();
Long getSAAT();
}
as seen in the example code for native query given above, cast return values to any value like as "SAAT", "DEGER" and then define interface "period" which have getDEGER() and getSAAT(). Even if I have not understand why parameter after get must be uppercase, in lowercase scenario it didn't work properly. ie. interface with getDeger(), getSaat() does not work properly in my case.
I'm having an strange problem when I try to retrieve some entities from the database. The table where the entities lives just have 4 rows. When I try select all rows I get a list where the first and the last elements are loaded correct, however, the second and the third has all properties as null. Here is a print of my debug console:
The entity is simple, as you can see below:
#Entity
#Table(name = "Empresa")
public class Empresa implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_EMPRESA")
private Integer idEmpresa;
#Basic(optional = false)
#Column(name = "NOME_EMPRESA")
#OrderColumn
private String nomeEmpresa;
#Column(name = "CNPJ")
private String cnpj;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "iDEmpresa", fetch = FetchType.LAZY)
private List<Cadastro> cadastroList;
}
If you want know how I am retrieving the entities, here is the code:
#Override
public List<T> recuperarTodos() {
Query query = entityManager.createQuery(criarQueryRecuperarTodos());
limitarQuantidadeDeRegistros(query);
return query.getResultList();
}
private String criarQueryRecuperarTodos() {
StringBuilder builder = new StringBuilder("SELECT e FROM ");
builder.append(classe.getSimpleName());
builder.append(" e");
builder.append(criarParametrosOrdenacao());
return builder.toString();
}
This is perfectly legal and expected situation. Hibernate uses dynamically generated proxies (hence javaassist objects, in the past hibernate used cglib as well) as placeholders for not fully fetched entities to allow lazy fetching. Because of this, generally speaking, you should not attempt to access attribute values directly. Using getters instead allows hibernate to issue an appropriate DB query and fill the entity. This can be a problem in some situations - for example, if the values are first requested outside the Hibernate session.
In my case I have a SQL query which looks like:
select * from event_instance where (object_id, object_type) in
(<LIST OF TUPLES RETRIEVED FROM SUBQUERY>);
I want to map this on Hibernate Entities and I have a problem with this query. My mapping looks like that:
#Entity
#Table(name="event_instance")
public class AuditEvent {
<OTHER_FIELDS>
#Column( name = "object_type", nullable = false)
private String objectType;
#Column( name ="object_id" , nullable = false)
private Integer objectId;
}
and second entity:
#Entity
#Table(schema = "els" ,name = "acg_objects")
public class AcgObject implements Serializable{
#Id
#Column(name = "acg_id")
private String acgId;
#Id
#Column(name="object_type")
private String objectType;
#Id
#Column(name="object_id")
private Integer objectId;
<OTHER FIELDS>
}
I already run query for getting AcgObjects and for my DAO I'm getting List only thing I want to do is query a touple using criteria like:
crit.add(Restrictions.in("objectType,objectId",<List of tuples>);
Is it possible? I was trying to use #Embedded object but don't know how exactly construct a query for it. Please help
You can do that not in standard SQL nor using criteria; you have to split in two distinct restrictions or using a Session.SQLQuery() if you want to use specific RDBMS (look at SQL WHERE.. IN clause multiple columns for an explanation)