spring data inheritance for repository reuse - java

I am using Spring Data to load an object and all works well...However, I don't want to load the entire object as I am returning a list to display in a table, so I only want to load what is in the table. then, when a user selects "details" I want to make an AJAX call to the server to load the entire object. My thought was to have a Base Class "TableView" then to have a subclass "Class DetailsView extends TableView". I could probably create a new repository, so one for the TableView and one for the DetailsView, but I'm wondering if there is a way to use the same repository class? below is an example of what I'd like to do, but I'm not sure how to change the repositoryClass to achieve what I want...I get the following error:
SQLGrammarException: could not extract ResultSet at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:261)
class TableView{
String title;
}
class DetailsView extends TableView{
String details;
}
interface ITableViewRepository extends CrudRepository<TableView, Integer>{

You can write two queries in your TableViewRepository.
One for returning id and title from you object
#Query("SELECT tv.id, tv.title FROM TableView tv")
TableView findWithTitles();
And after that just call a method findOne with TableView id to return entire object.

Related

SpringBoot: Better way to create multiple entities from a single JSON with all data

I am working on a REST API with the following structure:
controller: classes that define the endpoints to obtain/create entities.
model: classes that represent the entities that are stored in each database table.
repository: classes that extend JpaRepository, it provides the methods to perform HQL queries on each model.
service / serviceimpl: classes that define the logic to obtain or create an entity from a model.
There is a table in the database that has multiple #OneToMany relationships with other tables. From the front-end, I will receive a json with the data to create a new entity from this table, but this json will also contain information to create entities from other tables that are related to the main one. This gives me the following problems:
The model class for the main entity has a lot of #Transient attributes because they send me information that shouldn't be mapped directly to a DB table, because I'll have to implement the logic to create the actual instances. (where should I do it? currently the logic to get child instances is implemented in the parent's ServiceImpl class, so the code is very long and hard to maintain).
I must persist each instance separately: to create the child entities I must provide an id of the parent entity. Because of this, I need to use JpaRepository's .save() method a first time to insert the parent entity and get its id. Then from that id I do the logic to create all the child entities and persist each one. In case there is a problem in the middle of the method, some instances will have been persisted and others not, this implies saving incomplete data in the DB.
The result of this is a very dirty and difficult to maintain model and ServiceImpl class. But I have to do that, since the front-end devs want to send me a single json with the information of everything that needs to be created, and they decided that the back-end implements all the logic to create the entities.
In what classes and in what order would you define the methods to do this as cleanly and safely as possible?
If you use #Transactions and have auto-commit: false, it will commit the changes at the end of the transaction.
So if you created the main object, then create all other subsequent objects and if any of them fails, the transaction will rollback.
Regarding the order of creation:
i would make a creation manager that will handle these. So for example
the json that you receive from the FE is
Apply what says in this answer in the below method.
{
"name": "abc",
"children-ofTypeA": [{
"name": "abc-child-a"
},
"children-ofTypeB": [{
"name": "abc-child-b"
}],
"some-other-prop-that-we-don't-care": {..}
}
class MainObject {
private String name:
private List<A> childrenA;
private List<B> childrenB;
}
You get this json and you pass it to CreationManager for example
class CreationManager {
#Transactional
public void create(StructureAbove json) {
// use a mapper of something to create the object
var mainObj = createMainObjFrom(json);
//apply what says in the posted link
}
}

Lazy Loading in custom ORM

I am currently working on developing a simple Java web application without using an ORM.
It is a layered architecture. I use annotations to 'map' the columns from my domain class to my persistence layer where the repositories are.
My DefaultRepository is using reflection to get the field names and build the queries. I just use this one instead of making a separate one for each domain (such as user, order, product).
It looks like this:
Repository:
public abstract class DefaultRepository <TYPE extends DefaultDomain<TYPE>>{
public int insert(Connection con, TYPE entity){};
public int update (Connection con, TYPE entity){};
public int delete (Connection con, TYPE entity){};
public int findById(Connection con, int id){};
...
}
I want to implement lazy loading to load the orders of each user only when requested. This preferably happens in the repository in the findById() where I map the result set to my TYPE (domain class).
How would I go about implementing this foreign key relation/ one to many/many to one in general?
An idea was to make an annotation with the specific repository and then call the findAll() method in there when the order list is called.
For example:
public class Order extends DefaultDomain{
#ManyToOne(repository=UserRepository.class)
private User user;
}
Is that the right way? Is there a different/better approach to this?

Couchbase view for document deletion

I'm using couchbase server with spring data. Also for the crud operations I'm using spring org.springframework.data.repository.CrudRepository. I want to remove User documents which have same domain name. domain is a attribute of User pojo. I was able to fetch the documents based on the domain attribute value.
This is the my repo class.
public interface UserRepository extends CrudRepository<User, String>{
List<User> findByDomain(Query query);
void deleteByDomain(Query query);
}
Also the view for findByDomain is,
function (doc, meta) {
if (doc._class == "com.link.pojo.User") {
emit(doc.domain, null);
}
}
This is working for get all documents in same domain name. So I used the same view for deleteByDomain() function. It gives me an error.Seems like this view only work for fetch data. How can I remove documents which in same domain? Thanks.
org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.util.ArrayList<?> to type void for value '[com.link.pojo.User#21dfd606, com.link.pojo.User#6e5c3549, com.link.pojo.User#67ae8439, com.link.pojo.User#726aef5c]';
nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type java.util.ArrayList<?> to type void
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:176)
at org.springframework.data.repository.core.support.QueryExecutionResultHandler.postProcessInvocationResult(QueryExecutionResultHandler.java:75)
Your view needs to emit the object ID for each object in the view. Then take that array of IDs and for each one, call a delete on each of those IDs. If it fits your use case, a better way and should reduce the load on your cluster if there are a lot to delete is to set a random TTL between now and X hours/days/whatever on each object to be deleted. Then the Couchbase server will delete them as they are expired in a staggered fashion. If you need them deleted as soon as possible, then obviously use the delete call on the object IDs.

Generic method to update a field in database

I have a class that implement all my workflow method. At some pointing time, when the request is approved by the workflow, I need to update status in database. For this I need to call the respective service class to save the status. The following method is saving the status in db:
public void changeStatus(String employeeNumber, String carid,String Status) throws Exception {
Car car = carService.findCarByPrimaryKey(carid);
car.setStatus(Status);
carService.saveCarDetails(car);
}
I want to make this method generic since I don't have status for car only. I have to update status for different object depending from the application made. It can be for application for leave/parking...I can keep the field Status with the same name in all table. Please advise me how to proceed.
Thanks
I am not sure , what ORM you are using , like if JPA you are using , you can use find() with class name and primary key as parameters.
May be you can try adding a parameter in changeStatus() as Class class and while calling this changeStatus() method pass the class variable by using getClass() and can perform actions basis of that in changeStatus()

how to save values from one class object to another class object

I have two classes(Pojos) name Soldbookdetails.java and Bookdetails.java,
what I want to do is, I have to get data from Bookdetails table(Soldbookdetails.java) and save the same data to my Soldbookdetails table(Soldbookdetails.java).
ActionClass.java
private Double[] id;//With getter and setter
private Double[] quantity; //With getter and setter
Bookdetails book=new Bookdetails();//pojos,//With getter and setter
Soldbookdetails sbook=new Soldbookdetails();//pojos,//With getter and setter
BookdetailsDAO dao=new BookdetailsDAO();
SoldBooksTransactionDAO dao2=new SoldBooksTransactionDAO();
------------
(Note: my both pojo are same only their Class name are different)
My problem: I am unable to save record from Bookdetails.java to Soldbookdetails.java .(See My above ActionClass.java class,inside the execute method , i have mention the ERRROR).
After getting record by Bookid , i am unable to save the record into my Soldbookdetails.java.
Please help me to solve my problem.
Your saveSoldbooks(Soldbookdetails s) method takes an object of Soldbookdetails as argument but you are passing an object of class Bookdetails.
The thing you can do is you can add a method that copies the attributes of an Bookdetails object to an Soldbookdetails object (without the id field). Then you should try to save the object of Soldbookdetails using your existing method.
While keeping sold books and books in separated tables is (IMO) good perfomance issue, I think you don't need to create separated IDENTICAL classes for them.
Consider making you're class BookDetails an abstract and annotating it as MappedSuperclass:
#MappedSuperclass
public abstract class BookDetails{
// fields
// getters
// setters
}
#Entity
#Table(name="SoldBooks")
public class SoldBookDetails extends BookDetails{
// Currently blank
}
#Entity
#Table(name="BookDetails")
public class TradingBookDetails extends BookDetails{
// Currently blank
}
While currently you're classes are identical, at future you may decide to create others book types (like other table and classes for purchasing books to store or books in the way to customer) and, of course, there may appear different logic for SoldBooks and others, and in this case such 'abstraction' will simplify maintenance.
The only changes to you're saveSoldBook I currently see is to change it's argument type or provide type check in the body of the method, as long as while argument type is BookDetails, you can pass in the function any variable, derived from it - therefore, TraidingBookDetails, SoldBookDetails etc. (Changes needed depends on you're logic in this method and DAO itself).

Categories

Resources