how to persist only the properties that were assigned in spring crudrepository? - spring

I'm running in to a small problem with persisting an object. Here's an example of what my entity class looks like.
#Entity
public class Example(){
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private int number;
private String sentence;
/* No arg const, getters and setters omitted */
CrudRepository Interface:
#Repository
public interface ExampleRepository extends CrudRepository<Example, Integer>
{}
Service that implements the Interface:
#Service
public class ExampleService{
#Autowired
public ExampleRepository exampleRepository;
public void save(Example example){
exampleRespository.save(example)
}
}
Inside of CommandLineRunner:
Example example1 = new Example();
example1.sentence("Hello World!");
exampleService.save(example1);
Now the problem that I'm running into is that even though I didn't assign any value to the property number, it is still getting persisted as 0. How do I stop that property from getting assigned a value of 0 and make it null?

Change
private int number;
into
private Integer number;

the above solution is fine but again if you see in insert query for your save function, It insert all 3 column even you assigned only once column example1.sentence("Hello World!");
you can used #DynamicInsert(true) #DynamicUpdate(true) on Entity level,
this will fire query as
insert into example(sentence) values('Hello World!');
so query performance will increase

Related

How to make Set using spring-data-aerospike

Environment:
spring-boot v2.0.4 RELEASE
spring-data-aerospike v2.0.1.RELEASE
java - 8
Here are my application code and properties.
// application.properties
aerospike.hosts=xxx:3000
aerospike.namespace=test
// aerospike configuration class
#Configuration
#RequiredArgsConstructor
#EnableConfigurationProperties(AerospikeConfiguration.AerospikeConfigurationProperties.class)
#EnableAerospikeRepositories(basePackageClassses = TestAeroRepository.class)
public class AerospikeConfiguration extends AbstractAerospikeDataConfiguration {
private final AerospikeConfigurationProperties aerospikeConfigurationProperties;
#Override
protected Collection<Host> getHosts() {
return Host.parseServiceHosts(aerospikeConfigurationProperties.getHosts());
}
#Override
protected String nameSpace() {
return aerospikeConfigurationProperties.getNamespace();
}
#Data
#Validate
#ConfigurationProperties("aerospike")
public static class AerospikeConfigurationProperties {
#NotEmpty
String hsots;
#NotEmpty
String namespace;
}
}
# Entity class
#Value
#Document
#Builder(toBuilder = true)
#AllArgsConstructor
public class testEntity() {
#Id
int id;
#Field
String name;
#Field
String timestamp;
}
#Repository
public interface TestAeroRepository extends AerospikeRepository<TestEntity, Integer> {
}
public interface TestAeroService {
void save();
}
#Service
#RequiredArgsConstructor
public class TestAeroServiceImpl implements TestAeroService {
private final TestAeroRepository testAeroRepository;
#Override
public void save(TestEntity entity) {
testAeroRepository.save(entity);
}
}
I checked Aerospike client connection has no problem.
But error is occurred when save() method is executed.
org.springframework.cglib.core.ReflectUtils.defineClass(Ljava/lang/String;[BLjava/lang/ClassLoader;Ljava/security/ProtectionDomain;Ljava/lang/Class;)Ljava/lang/Class;
Have to make sets before execute the application? I didn't make sets.
Any problem with my code?
You’re using an old version of spring-data-aerospike (2.0.1.RELEASE was released on April 2019) is there any chance you can upgrade to the latest version? 2.4.2.RELEASE
You can see how to setup a simple spring data aerospike application here: https://medium.com/aerospike-developer-blog/simple-web-application-using-java-spring-boot-aerospike-database-and-docker-ad13795e0089
Please share the entire project’s code and the entire exception.
I would look into:
The configuration class (The Aerospike Beans creation).
The content of the testEntity class - are you using #Id annotation on the primary key field?
Extending the repository class with specifying the testEntity object (… extends AerospikeRepository<testEntity, Object> {) you can see an example in the link I added.
The set is automatically created and takes the name of your object class, which is testEntity in your case. For example, based on your code, if you do not specify a collection in the #Document annotation a set named "testEntity" will automatically be created. I added the #Document(collection = "testEntitys") annotation and all I did was create two set. Once you insert your first record, run the "SHOW SETS" aql command and it will be there. So that's one way to do it.

Spring data jpa search filter by foreign key and type

Model Class Vehicle
#Column(name="type",nullable=false)
private String type;
#Column(name="last_service_date",nullable=false)
private String lastServiceDate;
#Column(name="seats",nullable=false)
private Long seats;
#Column(name="bags_capacity",nullable=false)
private Long bagsCapacity;
#Column(name="milage",nullable=false)
private Long milage;
//for Franchise object id
private transient Long fId;
#ManyToOne
#JoinColumn(name="franchise_id")
private Franchise fkFranchiseId;
#Repository
public interface VehicleRepository extends JpaRepository<Vehicle,Long>
{
}
I am using spring data jpa repositories and want to search Vehicle by type and foreignKey=>(zipcode) how can i find
Just add a method in your Vehicle JPA repository interface as follow:
findAllByTypeAndFkFranchiseIdZipCode(String type, String zipCode);
And also you are welcome to check docs of Spring Data Jpa
List<Vehicle> findAllByTypeAndFkFranchiseId_ZipCode(String type, String zipCode);
You can use JPA repo method name query documented here https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
public interface VehicleRepo extends JpaRepository<Vehicle, String> {
List<Vehicle> findAllByTypeAndFkFranchiseIdZipCode((String type, String zipCode);
Page<Vehicle> findAllByTypeAndFkFranchiseIdZipCode((String type, String zipCode,Pageable page);
}
for those who have a more complex object and want to keep their code, u can also use #Query for fetching data.
u just need to do this like this:
#Repository
public interface VehicleRepo extends JpaRepository<Vehicle, String> {
#Query("from Vehicle v where v.type = :type and v.fkFranchise.zipCode = :zipCode")
List<Vehicle> findAllByTypeAndZipCode(String type, String zipCode);
}

How to paginate a list of object (not mapped domain object) using custom pagination with spring data

I have a repository called BananaRepositoryImpl that contains a function that return a list of BananaDTO ( the legacy code can't return the mapped entity ( Banana.java ),it's a constraint and I can't change this behavior :( )
public class BananaRepositoryImpl implements BananaRepository{
#Autowired
EntityManager em;
public List<BananaDTO> findAllBananes(){
//logic to get list of bananasDTO object types using Query query = em.createQuery(JPQL_QUERY_HERE);
}
}
Knowing that the BananaDTO object is a DTO for Banana.java class which looks like this :
#Data
#Entity
public class Banana{
private Long id;
private Double price;
private Double weight;
}
What I should do is to implement pagination over the findAllBananes() method so that I can return a Page using spring Data ( or another approach ).
Assuming the attributes of the BananaDTO is a subset of the Banana entities attributes you can use class-based projection support of Spring Data JPA, i.e. you just add a Pageable as a parameter to your method and return a Page<BananaDTO>:
interface BananaRepository extends CrudRepository<Banana, Long> {
Page<BananaDTO> findAllBananes(Pageable page)
}

I need help for persisting into oracle database

There is a problem about generating id while persisting into database.
I added the following code to my jpa entity file, however I'm getting 0 for personid.
#Id
#Column(unique=true, nullable=false, precision=10, name="PERSONID")
#SequenceGenerator(name="appUsersSeq", sequenceName="SEQ_PERSON", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "appUsersSeq")
private long personid;
EjbService:
#Stateless
public class EjbService implements EjbServiceRemote {
#PersistenceContext(name = "Project1245")
private EntityManager em;
#Override
public void addTperson(Tperson tp) {
em.persist(tp);
}
}
0 is default value for long type. The id will be set after invoking select query for the related sequence, which commonly is executed when you persist the entity. Are you persisting the entity? In case yes, post the database sequence definition to check it.

Lazy exception : size vs eager?

I was faced to a :
failed to lazily initialize a collection of role: ,no session or session was closed
When trying to access (from the controller, or a junit) the collection of "DataDictionaryEntry" that are in a "DataDictionary".
DataDictionary
#Entity
#Table( name = "IDS_RAVE_DATA_DICTIONARY",
uniqueConstraints={#UniqueConstraint(columnNames={"name"})
})
public class DataDictionary extends UnversionedObject {
#Column
private String name;
#OneToMany(mappedBy="dataDictionary",fetch=FetchType.EAGER)
private Collection<DataDictionaryEntry> dataDictionaryNames;
/* constructor */
public DataDictionary() {
super();
}
/* getters & setters */
}
DataDictionaryEntry
#Entity
#Table( name = "IDS_RAVE_DATA_DICTIONARY_ENTRY",
uniqueConstraints={#UniqueConstraint(columnNames={"dataDictionary","codedData"})
})
public class DataDictionaryEntry extends UnversionedObject {
#ManyToOne
#JoinColumn(name="dataDictionary")
private DataDictionary dataDictionary;
#Column
private String codedData;
#Column
private Integer ordinal;
#Column
private String userDataString;
#Column
private Boolean specify;
/* constructor */
public DataDictionaryEntry() {
super();
}
/* getters & setters */
}
I do have an abstract service object and another service extending it :
Generic service
#Transactional
public abstract class RaveGeneralServiceImpl<T> implements RaveGeneralService<T> {
private JpaRepository<T, Long> repo;
/**
* Init the general rave services with your specific repo
* #param repo
*/
protected void init(JpaRepository<T, Long> repo){
this.repo = repo;
}
#Override
public List<T> findAll(){
return repo.findAll();
}
#Override
public T save(T obj){
return repo.save(obj);
}
#Override
public void flush(){
repo.flush();
}
}
DataDictionaryServiceImpl
#Service
public class DataDictionaryServiceImpl extends RaveGeneralServiceImpl<DataDictionary> implements DataDictionaryService {
#Resource
private DataDictionaryRepository dataDictionaryRepository;
#PostConstruct
public void init() {
super.init(dataDictionaryRepository);
}
}
I could find replies on how to solve it. The first solution often seen is to change to LAZY to a EAGER. When I printed the generated query when accessing a FINDALL() method it shows the following :
Hibernate:
/* select
generatedAlias0
from
DataDictionary as generatedAlias0 */ select
datadictio0_.ID as ID81_,
datadictio0_.createdByUser as createdB2_81_,
datadictio0_.createdTime as createdT3_81_,
datadictio0_.lastUpdateTime as lastUpda4_81_,
datadictio0_.lastUpdateUser as lastUpda5_81_,
datadictio0_.VERSION as VERSION81_,
datadictio0_.name as name81_
from
IDS_RAVE_DATA_DICTIONARY datadictio0_
Hibernate:
/* load one-to-many com.bdls.ids.model.rave.DataDictionary.dataDictionaryNames */ select
datadictio0_.dataDictionary as dataDic11_81_1_,
datadictio0_.ID as ID1_,
datadictio0_.ID as ID82_0_,
datadictio0_.createdByUser as createdB2_82_0_,
datadictio0_.createdTime as createdT3_82_0_,
datadictio0_.lastUpdateTime as lastUpda4_82_0_,
datadictio0_.lastUpdateUser as lastUpda5_82_0_,
datadictio0_.VERSION as VERSION82_0_,
datadictio0_.codedData as codedData82_0_,
datadictio0_.dataDictionary as dataDic11_82_0_,
datadictio0_.ordinal as ordinal82_0_,
datadictio0_.specify as specify82_0_,
datadictio0_.userDataString as userDat10_82_0_
from
IDS_RAVE_DATA_DICTIONARY_ENTRY datadictio0_
where
datadictio0_.dataDictionary=?
The 2nd solution we often see is to make a call to the .size() of the component that is being lazily initialized. So indeed by changing my service to this :
#Service
public class DataDictionaryServiceImpl extends RaveGeneralServiceImpl<DataDictionary> implements DataDictionaryService {
#Resource
private DataDictionaryRepository dataDictionaryRepository;
#PostConstruct
public void init() {
super.init(dataDictionaryRepository);
}
#Override
public List<DataDictionary> findAll() {
List<DataDictionary> results = super.findAll();
for (DataDictionary dd : results) {
dd.getDataDictionaryNames().size();// init lazy
}
return results;
}
}
The lazy exception is also gone ! But the end result is the same query... So the what is the added value of keeping it LAZY if the end-query is the same ? Or did I do it wrong ?
Suppose that for the front-end you would have a data table that displays only basic information (the name for example), it would call the findAll() but still query the complete dependencies of that object ?
While the results with this method are pretty much exactly the same, the value of keeping it lazy is that if you don't need it fetched in other queries, you don't automatically have it eagerly fetched. Making the relationship eager applies to every method of accessing that entity, while calling size on a collection forces it to be fetched for that one occurrence.
There are other ways that might be more efficient, such as using a join fetch qualifier in the JPA query itself, allowing the provider to fetch the relationship using a single select.
You can either use: Hibernate.initialize() to initialize Lazy collections.
Or using spring to avoid LazyException use filer in your web.xml:
<filter>
<filter-name>hibernateFilterChain</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
But remember, using lazy fetching is bad idea if you are thinking about good application design and performance.

Resources