Spring: map entity to a scheme - spring-boot

Im trying to create a Spring-Boot Data JPA-Application with Entities based in multiple schemes using an oracle Database.s
I have two Schemes, scheme_a and scheme_b. The DDL User for scheme_a is scheme_a, the DDL user for scheme_b is scheme_b. Both DDL user will be used by liquibase to create my initial table structure.
My application has two entities:
Entity foo is managed by my application and should be based in scheme scheme_a.
Entity bar is managed by a third party library and should be based in scheme scheme_b.
My application has a user app_user, with CRUD-rights on all tables and sequences located in scheme_a and scheme_b. This user is my DMA-user
My plan was to use Spring-Data-Jpa to connect with the database using the app-user user. This user should be able to work with all entities in scheme_a and scheme_b.
Example of Entity foo (bar has identical structure):
#Entity
#Table(name = "T_FOO")
public class FooEntity {
public FooEntity () { // no-args c-tor for hibernate
}
#Id
#Column(name = "foo_id")
#SequenceGenerator(name = "sequence_foo_id", sequenceName = "sequence_foo_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_foo_id")
private long id;
#Column(name = "foo_name")
private String name;
}
Every entity has its own Repository:
public interface FooRepo extends CrudRepository<FooEntity, Long> {
...
}
My configuration:
#Configuration
#EnableJpaRepositories(basePackageClasses = {FooRepo.class, BARRepo.class})
#EntityScan(basePackageClasses = {FooEntity.class, BarEntity.class})
public class AppDBConfig {
...
}
But every time my application tries to start it is not able to locate the table T_FOO based in scheme_a.
I am not able to extend the #Table-Annotation with corresponding scheme. Does any one know a way to solve this problem? Is it possible to create something like a "scheme-table" to tell hibernate in which scheme which entity is located, like
var schemeMap = new HashMap<Class, String>();
schemeMap.put(FooEntity.class, scheme_a);
schemeMap.put(BarEntity.class, scheme_b);
Greetings from Germany!

You need to specify the schema in the #Table annotation.
#Entity
#Table(name = "T_FOO", schema = "scheme_a")
public static void FooEntity {
// ..
Since you don't seem to be allowed to change the annotation on FooEntity I see a couple of options available to you:
If you can change the annotation on BarEntity but not on FooEntity you can make the schema of FooEntity your default schema and set the schema for BarEntity in the annotation.
If you can't change either entity but have some control over the database you can create a view or synonym in your main schema that mirrors T_FOO.
You can also configure Hibernate with XML and specify the schema there.
You could decompile the class file containing FooEntity, add the required annotation and compile it again.
You probably could use ByteBuddy or a similar tool to do that at runtime during startup of your application.

Related

Springboot Joint table from different database

I have a Springboot project with two datasource configured one for each database I'm using. Everything works, but I need to create an Entity in database one that refers to an entity from database 2. The problem is that the entity in the second database is not found.
#Entity
#Table(name = "data", catalog = "data")
public class Data implements Serializable
{
//all stuff related to data here.
#ManyToOne
private User user;
//Entity User is store in the second database
}
Is there anyway to tell spring that the entity User can be found in the second datasource?

How to make #Indexed as unique property for Redis model using Spring JPA Repository?

I have a model class that I store in Redis and I use Jpa Repository with Spring java. Normally(not with redis) jpa repository is saving the new data or updates(conditionally) if the given model is already exist in Db. Here, I want to add new item to redis but if it is not already exists on db otherwise update it just like usual Jpa implementation.
Here is my model:
#Getter
#Setter
#RedisHash("MyRecord")
public class MyRecordRedisModel {
private String id;
#Id
#Indexed
private String recordName;
private Date startDate;
private Date endDate;
}
And my repository class is just a normal spring jpa repo as follows:
#Repository
public interface IFRecordRedisRepository extends JpaRepository<IFRecordRedisModel, String> {
Page<IFRecordRedisModel> findAll(Pageable pageable);
}
Unique key must be the name (I totally do not care about uniquiness of the id). Thus, if the name is already exist in Db than do not add it again. I marked it as Indexed but still it is adding same data (with same recordName).
How can I make it unique?
This would require an additional query, but I think this solution would work for you. You can use query by Example to check if there exists a record with that name, and save conditionally, or do something else if it already exists.
IFRecordRedisModel exampleRecord = new IFRecordRedisModel();
exampleRecord.setRecordName(inputRecord.getRecordName());
if (!repository.exists(Example.of(exampleModel)))
repository.save(inputRecord);
else ..... // do something else

Spring data jpa does not update existing row (Oracle) when using #sequencegenerator

New to spring data JPA. I have sequence created in oracle table. I am using JPARepository saveall() method to save the data. Inserts work without any problem but when i try to update any existing rows in the table it always tries to insert throwing unique constraint error since i have unique index created for that table.
Entity Class
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator1")
#SequenceGenerator(sequenceName = "emp_seq", name = "generator1",allocationSize = 1)
#Column(name = "USER_ID")
private Long id;
Save method invocation
public void persistEmployees(List<Employee> employees) {
employeeRepo.savaAll(employees);
}
Repository class
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> { }
How can i tell JPA to look for existing row before inserting? Any help is much appreciated!!!
In My Humble Opinion;
Using "Exists" condition-check as "sub-query" for all constrained columns, before Update will solve this.

Multiple Repositories for the Same Entity in Spring Data Rest

Is it possible to publish two different repositories for the same JPA entity with Spring Data Rest?
I gave the two repositories different paths and rel-names, but only one of the two is available as REST endpoint.
The point why I'm having two repositories is, that one of them is an excerpt, showing only the basic fields of an entity.
The terrible part is not only that you can only have 1 spring data rest repository (#RepositoryRestResource) per Entity but also that if you have a regular JPA #Repository (like CrudRepository or PagingAndSorting) it will also interact with the spring data rest one (as the key in the map is the Entity itself).
Lost quite a few hours debugging random load of one or the other. I guess that if this is a hard limitation of spring data rest at least an Exception could be thrown if the key of the map is already there when trying to override the value.
The answer seems to be: There is only one repository possible per entity.
I ended up using the #Subselect to create a second immutable entity and bound that to the second JpaRepsotory and setting it to #RestResource(exported = false), that also encourages a separation of concerns.
Employee Example
#Entity
#Table(name = "employee")
public class Employee {
#Id
Long id
String name
...
}
#RestResource
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long> {
}
#Entity
#Immutable
#Subselect(value = 'select id, name, salary from employee')
public class VEmployeeSummary {
#Id
Long id
...
}
#RestResource(exported = false)
public interface VEmployeeRepository extends JpaRepository<VEmployeeSummary, Long> {
}
Context
Two packages in the monolithic application had different requirements. One needed to expose the entities for the UI in a PagingAndSortingRepository including CRUD functions. The other was for an aggregating backend report component without paging but with sorting.
I know I could have filtered the results from the PagingAndSorting Repository after requesting Pageable.unpaged() but I just wanted a Basic JPA repository which returned List for some filters.
So, this does not directly answer the question, but may help solve the underlying issue.
You can only have one repository per entity... however, you can have multiple entities per table; thus, having multiple repositories per table.
In a bit of code I wrote, I had to create two entities... one with an auto-generated id and another with a preset id, but both pointing to the same table:
#Entity
#Table("line_item")
public class LineItemWithAutoId {
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
...
}
#Entity
#Table("line_item")
public class LineItemWithPredefinedId {
#Id
private String id;
...
}
Then, I had a repository for each:
public interface LineItemWithoutId extends Repository<LineItemWithAutoId,String> {
...
}
public interface LineItemWithId extends Repository<LineItemWithPredefinedId,String> {
...
}
For the posted issue, you could have two entities. One would be the full entity, with getters and setters for everything. The other, would be the entity, where there are setters for everything, but only getters for the fields you want to make public. Does this make sense?

Spring, JPA -- integration test of CRUD of entity which has many transitive dependencies of other entities

I have entity e.g. Product which aggregates other entities such as Category. Those entities can also aggregate other entities and so on. Now I need to test my queries to database.
For simple CRUD I would create mock of EntityManager. But what if I have more complex query which I need to test for correct functionality. Then I probably need to persist entity (or more of them) and try to retrieve/update, whatever. I would also need to persist all entities on which my Product depends.
I don't like such approach. What is the best way to test such queries?
Thanks for replies.
Update -- example
Lets assume following entity structure
This structure is maintained by JPA implementation. For example Product class would look like this
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#ManyToOne
private Category category;
#ManyToOne
private Entity1 something;
}
So now if I want to test any query used in DAO I need to create Product in database, but it is dependent on Category and Entity1 and there is #ManyToOne annotation so values cannot be null. So I need to persist those entities too, but they have also dependencies.
I'm considering pre-creating entities such Category, Entity1 and Entity2 before test using SQL script or dbunit (mentioned by #chalimartines) which would save large amount of code, but I don't know whether it is good solution. I would like to know some best practices for such testing.
you can use #TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true) as
#ContextConfiguration(locations={"classpath:/path/to/your/applicationContextTest.xml"})
#RunWith( SpringJUnit4ClassRunner.class)
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class YourClassTest {
#Test
public void test() {
//your crud
}
}
update
You cant set the dependecies to null in order to avoid to persist them
I don't know other way, but for persisting Product and its dependencies you can use testing framework DBunit that helps you setup database data.

Resources