I've using spring data JPA repositories to save the data into my tables.
In one of the situation, I've to store data in two different tables. These two tables have the exact same schema. But I can only store in one table as JpaRepository maps to just one table.
Example:
#Entity
#Table(name="users")
class User {
private Long userId;
private String firstName;
private String lastName;
}
interface MyRepo1 extends JpaRepositories<User,Long> {
}
interface MyRepo2 extends JpaRepositories<User,Long> {
}
Is there a way to map a single entity into multiple JpaRepositories? So, when I call MyRepo1.save(user) it saves in Users table and when I call MyRepo2.save(user), it saves in BackupUsers(exact same schema as Users) table.
Thanks
You should have two different entities, for instance, User entity AppUser entity, each one of them pointing to the different tables like this, assuming that the two table names are users and app_users:
#Entity
#Table(name="users")
public class User extends SuperUser {...}
and
#Entity
#Table(name="app_users")
public class AppUser extends SuperClass {...}
Of course, to avoid code duplication you can put your table fields in a superclass named SuperClass, for example:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class SuperUser {
#Id
private Long userId;
private String firstName;
private String lastName;
// getters and setters, constructors
}
After, you need to create two repositories for each entity class:
public interface UserRepository extends JpaRepositories<User, Long> {
}
public interface AppUserRepository extends JpaRepositories<AppUser,Long> {
}
NOTE: To finish, it's not recommended at all to have two tables that hold the same fields.
I don't think you can save in different tables with two different repositories, because you can't specify the table name in repository, but in the entity, I would suggest to use :
// class which hold common fields
class User {
private Long userId;
private String firstName;
private String lastName;
}
// entity for table 1
#Entity
#Table(name="table1")
class User1 extends User {}
// entity for table 1
#Entity
#Table(name="table2")
class User2 extends User {}
// repo for entity 1
interface MyRepo1 extends JpaRepositories<User1,Long> {}
// repo for entity 2
interface MyRepo2 extends JpaRepositories<User2 ,Long> {}
Related
So I have the following application, which has one entity called Product that inherits two other entities (Product > Bike, Product > Wheel). Controllers look like this:
public abstract class ProductController<T extends Product> {
#Autowired
private ProductService<T> productService;
#PostMapping
public ResponseEntity post(#RequestBody T product) {
return ResponseEntity.ok(productService.save(product));
}
#GetMapping
public ResponseEntity get() {
return ResponseEntity.ok(productService.findAll());
}
}
#RestController
#RequestMapping("/products/categories/bikes")
public class BikeController extends ProductController<Bike> {}
#RestController
#RequestMapping("/products/categories/wheels")
public class WheelController extends ProductController<Wheel> {}
Entities:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
public Product() {}
//getters and setters
}
#Entity
public class Bike extends Product {
private String color;
public Bike() {}
//getters and setters
}
#Entity
public class Wheel extends Product {
private Double diameter;
public Wheel() {}
//getters and setters
}
Product repository:
public interface ProductRepository<T extends Product> extends CrudRepository<T, Long> {}
Product service:
#Service
public class ProductService<T extends Product> {
#Autowired
private ProductRepository<T> productRepository;
public T save(T product) {
return productRepository.save(product);
}
public Iterable<T> findAll() { return productRepository.findAll(); }
}
After running the program it creates three tables for each entity. If i call the post method from the concrete controller it adds the entity to its table. But the findAll() method returns entities not from the concrete table but from the product table. So my question is why is this happening (even if i specified the Entity type in the repository)?
What you want to achive is impossible because Bike is a subtype of Product in java but not for JPA. In the Database it usally split into different Tables for each Subtype and only the tables (seen by JPA as entites) can be queried. So a Spring Repository can't query it either, because it uses JPA internally.
Please take a look here and read more about jpa inheritance: https://www.baeldung.com/hibernate-inheritance
Generally: It is bad pratice to have different table for each Type of Product. Everytime you add a new Product you would have to add a whole new class and table in database. It is best practice to just have a single entity/class (and thus a single table) for Product and a field to distinguish between different types of products. In it's simplest form a String productType, but i would recommand using a seperate Entity ProductType with an id and name (in its simplest form) and have a #OneToMany relation between Product and ProductType. Additonal data like color and diameter could be stored using a field of type Map with #ElementCollection or in a another entity for (dynamic) additional data (as seen here: https://stackoverflow.com/a/15061468/7142748).
Is it possible to map a baseTable with a base class and tell to JPA tool to not insert in the class the fileds that are in the baseTable?
I have the field creation-date which i want in every table of my db, so i created a baseTable with that field and the other tables extend this baseTable.
When i generate the classe for mapping this structure, japtool creates for me each table with creation-date field, which clearly i'd want just in baseEntity class and not in every child class.
There is a way to accomplish it?
If I understood your answer correctly, I think you are looking for JPA Inheritance
#MappedSuperclass
public class BaseEntity {
#Id
protected Integer id;
protected Date createdDate;
...
}
#Entity
public class EntityA extends BaseEntity {
protected String otherAttribs;
...
}
#Entity
public class EntityB extends BaseEntity {
protected Float differentAttribs ;
...
}
Im my SQL Server Database I have 8 tables with the same structure.
Now I want to insert in selected tables with one Java class.
#Entity
#Table(name = "tbl_Prognosen") //here I want to put all table-Names
public class AZBNachricht { ...
is this possible?
It isn't possible to accomplish what you described.
The closest to code reuse at the entity class level would be to use a #MappedSuperclass class where you place all the shared column names, etc and then extend that for each table implementation with differing table names.
#MappedSuperclass
public abstract class AbstractStructure {
#Id
#GeneratedValue;
private Integer id;
private String column1;
private String column2;
}
#Entity
#Table(name = "table1")
public class Entity1 extends AbstractStructure {
}
// ... so on
I have problems with defining a schema with multiple level inheritance,
so in my case I have a schema like bellow :
Model(id,created)
UserModel extends Model (login,password)
CustomerModel extends UserModel (orders)
StoreOwnerModel extends UserModel (stores)
ProductModel extends Model(name,price)
I have set inheritance strategy in Model on TABLE_PER_CLASS, so that means that I want for each sub class of Model create a table.
and the inheritance strategy in UserModel is set to SINGLE_TABLE to have just one table for all UserModel's subClasses.
But in my data base I see that for each UserModel subclasses a table is generated.
and I can't find the DiscriminatorColumn user_type in the generated table table USERS corresponding to UserModel.
here are my entities:
Model.class
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
#MappedSuperclass
public abstract class Model {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
private Integer id;
#DateTimeFormat(pattern="dd/MM/yyyy hh:mm:ss")
private Date created;
//getters/setters
}
UserModel.class
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="user_type",discriminatorType=DiscriminatorType.STRING)
#SecondaryTable(name="USERS")
#DiscriminatorValue("user")
public class UserModel extends Model{
#Column(unique=true)
private String login;
//getters & setters
}
CustomerModel.class
#Entity
#DiscriminatorValue(value="customer")
public class CustomerModel extends UserModel{
private List<OrderModel> orders;
//getters & setters
}
StoreOwnerModel.class
#Entity
#DiscriminatorValue(value="store_owner")
public class StoreOwnerModel extends UserModel{
private List<StoreModel> stores;
//getters & setters
}
ProductModel.class
#Entity
public class StoreOwnerModel extends UserModel{
private String name;
private double price;
//getters & setters
}
PS: this is not a duplucated Question, I dont Find this Answer on any of previous ones.
according to #chris I should remove #Inheritance from Model entity
and I also removed #SecondaryTable(name="USERS") from UserModel and it worked just perfectly.
I have two hibernate classes: a base class, and an extended class that has additional fields. (These fields are mapped by other tables.)
For example, I have:
#Entity
#Table(name="Book")
public class A {
private String ID;
private String Name;
// ...
}
#Entity
#Table(name="Book")
public class B extends A {
public String node_ID;
// ...
}
public class Node {
public String ID; // maps to B.node_ID
// ...
}
How do I map this in Hibernate? The hibernate documentation states three types of inheritence configurations: one table per class, one table with a type column, and a join table -- none of which apply here.
The reason I need to do this is because class A is from generic framework that's reused over multiple projects, and class B (and Node) are extensions specific to one project -- they won't be used again. In the future, I may have perhaps a class C with a house_ID or some other field.
Edit: If I try the above pseudo-code configuration (two entities mapped to the same table) I get an error that the DTYPE column doesn't exist. The HQL has a "where DTYPE="A" appended.
This is possible by mapping the #DiscriminatorColumn and #DiscriminatorValue to the same values for both classes; this can be from any column you use that has the same data regardless of which type (not sure if it works with null values).
The classes should look like so:
#Entity
#Table(name="Book")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="published")
#DiscriminatorValue(value="true")
public class A {
private String ID;
private String Name;
// ...
}
#Entity
#Table(name="Book")
#DiscriminatorValue(value="true")
public class B extends A {
public String node_ID;
// ...
}
For anyone who got here like me and does not want to have the dtype column but instead want to use the same table for more than one entity as is I would recommend using this
Basically you can create a Base like this
#MappedSuperclass
public abstract class BaseBook<T extends BaseBook> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
... any other variables, getters + setters
}
#Entity
#Table(name= "book")
public class BookA extends BaseBook<BookA>{
//Default class no need to specify any variables or getters/setters
}
#Entity
#Table(name= "book")
public class BookB extends BaseBook<BookB>{
#Column(name = "other_field")
private String otherFieldInTableButNotMapedInBase
... Any other fields, getter/setter
}
From the above we have created base super class which does not have any entity or table mapping. We then create BookA to be default with the Entity + Table mapping. From there we can create other Entities all extending from BaseBook but pointing to one table