I am having a faq entity as below. Here createdBy field is having a manyToOne relationship with the user entity. Below joinColumns shows the association.
In the User entity, i have OneToMany relationship with UserRoles and UsersUnit which is EAGER load for User and not for faq. So i added #JsonIgnoreProperties
for UsersUnit and UsersRole and the corresponding User entity is shown below.
#Entity
#Table(name = "FAQ", catalog="abc")
public class Faq implements Serializable {
public Faq() {
super();
}
#Column(name = "CREATE_DATE")
private Timestamp createDate;
#Where(clause = "DELETE_DATE is null")
#Column(name = "DELETE_DATE")
private Timestamp deleteDate;
#Column(name = "DELETED_BY")
private BigDecimal deletedBy;
#Column(name = "DOC_BLOB", nullable = false)
#JsonIgnore
private byte[] docBlob;
#Column(name = "DOC_NAME", nullable = false, length = 100)
private String docName;
#Id
private BigDecimal id;
#Column(name = "ORDER_BY")
private BigDecimal orderBy;
#Column(name = "UPDATE_DATE")
private Timestamp updateDate;
#Column(name = "UPDATED_BY")
private BigDecimal updatedBy;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name="created_by", referencedColumnName="id")
})
private User faqCreatedBy;
}
User entity:
#Entity
#Table(name = "USERS", catalog="abc")
#JsonInclude(Include.NON_NULL)
public class User extends EntityLog{
private BigDecimal id;
private BigDecimal edipi;
private String firstname;
private String lastname;
private String email;
..///
private Set<UsersRoles> userRoles;
private Set<UsersUnit> usersUnit;
#Id
#Column(name="id")
public BigDecimal getId() {
return id;
}
...///
#Column
#JsonIgnoreProperties({ "faqCreatedBy" })
#OneToMany(fetch = FetchType.EAGER,mappedBy = "user",cascade = {CascadeType.ALL})
#JsonManagedReference
public Set<UsersRoles> getUserRoles() {
return userRoles;
}
...///
#Column
#JsonIgnoreProperties({ "faqCreatedBy" })
#OneToMany(fetch = FetchType.EAGER,mappedBy = "user",cascade = {CascadeType.ALL})
#JsonManagedReference
public Set<UsersUnit> getUsersUnit() {
return usersUnit;
}
////...
}
With this change I am expecting the faq to load with User entity but I am not execting UsersRoles and UsersUnit to load.
But that is not what i see. When faq loads it loads User and UsersRoles and UsersUnit. I am using Spring JPA fyi. Any leads what is wrong ? Appreciate any inputs.
Related
I have created JPA entities class. But using basic query taking humongous amount of time for basic sql query having 100 records in database.
I have 4 tables. (Group/GroupA/GroupB/GroupC) having below structure.
#Table(name = "group")
public class Group implements Serializable {
#Id
#Column(name = "id")
private String id;
#Column(name = "publish_date")
private LocalDate publishDate;
#OneToOne(mappedBy = "group", cascade = CascadeType.ALL)
private GroupA groupA;
#OneToOne(mappedBy = "group", cascade = CascadeType.ALL)
private GroupB groupB;
#OneToOne(mappedBy = "group", cascade = CascadeType.ALL)
private GroupC groupC;
}
#Table(name = "groupA")
public class GroupA {
#Id
#Column(name = "group_id")
private Long groupID;
#Column(name = "name")
private String name;
#OneToOne
#JoinColumn(name = "id")
#JsonIgnore
private Group Group;
}
#Table(name = "groupB")
public class GroupB {
#Id
#Column(name = "group_id")
private Long groupID;
#Column(name = "name")
private String name;
#OneToOne
#JoinColumn(name = "id")
#JsonIgnore
private Group Group;
}
#Table(name = "groupC")
public class GroupC {
#Id
#Column(name = "group_id")
private Long groupID;
#Column(name = "name")
private String name;
#OneToOne
#JoinColumn(name = "id")
#JsonIgnore
private Group Group;
}
Repository class:
#Repository
public interface GroupRepository extends JpaRepository<Group, Long> {
#Query("select r from Group r WHERE r.publishDate = ?1")
List<Group> findAllGroupForDate(LocalDate businessDate);
}
The above basic query is taking 1 minute 30 seconds for around 100 rows in Main Group table.
Please help if I am making anything wrong in entity class.
THanks.
Try to use the Lazy loading concept.
#OneToOne(mappedBy = "group", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
I have two spring boot entities MeetingSetting and MeetingTime, MeetingSetting can have multiple MeetingTimes. I am trying to save these to at the same time with the DTO structure, so I can avoid the circular reference problem when I am getting MeetingTimes. Saving partially works. MeetingSettings has a property called meetingName which is a foreign key in meetingTimes. Everything except meetingName is saved which is for some reason null, but I can not find the reason, could someone maybe look at my code and tell me what I am missing?
MeetingSetting Entity:
#Entity
#Table(name = "meeting_settings")
#Setter
#Getter
public class MeetingsSetting implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_name", unique = true)
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
#OneToMany(mappedBy = "meetingName", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<MeetingTime> meetingTime = new HashSet<>();
}
MeetingSettingDTO:
#Getter
#Setter
public class MeetingSettingDTO {
private Long id;
#NotNull
private String meetingName;
#NotNull
private String meetingUrl;
#NotNull
private String meetingPw;
private Set<MeetingTime> meetingTime;
}
MeetingTime Entity:
#Entity
#Table(name = "meeting_times")
#Getter
#Setter
public class MeetingTime implements Serializable {
#JsonIgnore
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#Column(name = "start_time")
private String startTime;
#Column(name = "end_time")
private String endTime;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "meeting_name" , referencedColumnName = "meeting_name")
private MeetingsSetting meetingName;
}
MeetingTimeDTO:
#Getter
#Setter
public class MeetingTimeDTO {
private Long id;
#NotNull
private String date;
#NotNull
private String startTime;
#NotNull
private String endTime;
private Set<MeetingSettingDTO> meetingSettings;
}
And finally the controller where I am saving everything (Just save method):
#PostMapping("/")
public void saveMeeting(#RequestBody MeetingSettingDTO meetingSettingDTO){
MeetingsSetting meetingsSetting = new MeetingsSetting();
meetingsSetting.setMeetingName(meetingSettingDTO.getMeetingName());
meetingsSetting.setMeetingPw(meetingSettingDTO.getMeetingPw());
meetingsSetting.setMeetingUrl(meetingSettingDTO.getMeetingUrl());
Set<MeetingTime> meetingTimeSet = meetingSettingDTO.getMeetingTime();
meetingsSetting.setMeetingTime(meetingTimeSet);
meetingSettingService.saveMeeting(meetingsSetting);
}
My service is just implementing a jpaRepository which takes MeetingSetting as parameter
In your MeetingTime entity class you have a parent:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "meeting_name" , referencedColumnName = "meeting_name")
private MeetingsSetting meetingName;
You have to set it explicitly for each MeetingTime, so add this:
Set<MeetingTime> meetingTimeSet = meetingSettingDTO.getMeetingTime();
meetingTimeSet.forEach(m -> m.meetingName(meetingsSetting));
I have two tables, user and transaction. Where one user can have many transactions. So, everytime I create new user, they automatically make new transaction and the transaction type is SEND MONEY. But I don't understand how to write it in Spring JPA. Please take a look on my code and help me.
User.java
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#Column(name = "password")
private String password;
#Column(name = "money")
private int money;
//Getter Setter Constructor
}
Transaction.java
#Entity
#Table(name = "transaction")
public class Transaction {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_trans")
private long id_trans;
#Column(name = "id_user")
private long id_user;
#Column(name = "transaction_date")
private Timestamp transaction_date;
#Column(name = "type") //Default set as "SEND MONEY"
private String type;
#Column(name = "trans_money") //From money in User.class
private int trans_money;
//Getter Setter Constructor
}
I know I should do something in my UserDAO.java, but I still don't know how to send data from body and split(?) it into two object (user and transaction, so I can persist it in UserDAO).
First of all, you have to write the relationship between User and Transaction.
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#Column(name = "password")
private String password;
#Column(name = "money")
private int money;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private Set<Transaction> transactions = new HashSet<>();
//Getter Setter Constructor
}
#Entity
#Table(name = "transaction")
public class Transaction {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_trans")
private long id_trans;
#Column(name = "id_user")
private long id_user;
#Column(name = "transaction_date")
private Timestamp transaction_date;
#Column(name = "type") //Default set as "SEND MONEY"
private String type;
#Column(name = "trans_money") //From money in User.class
private int trans_money;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(referencedColumnName = "id")
private User user;
//Getter Setter Constructor
}
Then you have to create the JPA repository interface for the User
#Repository
public interface UserRepo extends CrudRepository <User, Long> {
}
Then in a service, you can do the following
#Service
public class UserService {
private UserRepo userRepo;
#Autowired
MealService(UserRepo userRepo){
this.userRepo = userRepo;
}
public void CreateNewUser(){
User user = new User();
// set its values
Transaction transaction = new Transaction();
transaction.setType("SEND MONEY");
// set other values
user.getTransactions().add(transaction);
userRepo.save(user);
}
}
Looking at the #Entity classes mentioned it seems to me that there exists an #ManyToOne association between Transaction and User which is not captured in the entity relationship modeling/mapping.
Please consider modeling that in your Transaction entity as follows,
#Entity
#Table(name = "transaction")
public class Transaction {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_trans")
private long id_trans;
#ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE}, fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private User user;
#Column(name = "transaction_date")
private Timestamp transaction_date;
#Column(name = "type") //Default set as "SEND MONEY"
private String type;
#Column(name = "trans_money") //From money in User.class
private int trans_money;
//Getter Setter Constructor
}
Once you do that you can create a JPA repository class for Transaction and User and simply use the save method to do what you want in a transaction after constructing your instances. More on transactions in Spring Data JPA here
public interface TransactionRepository extends JpaRepository<Transaction, Long> {
}
I had entity for JSON parsing
#Entity
public class Product{
private int productId;
private String productName;
private BigDecimal productPrice;
private int productVendorId;
private String productVendorName;
private int productCategoryId;
private String productCategoryName;
//getters setters here
created 3 tables in dataBase:
products (product_id, product_name,product_price, product_vendor_id), product_category_id);
vendors(vendor_id, vendor_name); categories (category_id, category_name);
in 1st table product_vendor_id fk -> vendor_id pk in vendors and product_category_id fk -> category_id pk in categories
i tried something like this:
#Entity
#Table(name = "products, schema = "market")
public class Product
#Id
#Column(updatable = false, nullable = false, name = "product_id")
private int Id;
#Column(name = "product_name")
private String productName;
#Column(name = "product_price")
private BigDecimal productPrice;
#Column(name = "product_vendor_id")
private int productVendorId;
#Columnt(table = "vendors", name = "vendor_name")
private String vendor_name;
#Column(name = "product_category_id")
private int productCategoryId;
#Column(table = "categories", name = "category_name")
private String productCategorName;
//getters setters here
received alot of errors: like i have not category_name column in products table etc. this error i received when used
#Table(name = "products", schema = "market" )
#SecondaryTables({#SecondaryTable(name = "vendors", schema = "market"),
#SecondaryTable(name = "categories", schema = "market")})
#JsonIgnoreProperties(ignoreUnknown = true)
public class Product {
....
#JoinColumn(name = "product_vendor_id", referencedColumnName = "vendor_id")
private int productVendorID;
#JoinColumn(table = "vendors", name = "vendor_name")
private String productVendorName;
#JoinColumn(name = "product_category_id", referencedColumnName =
"product_category_id")
private int productCategoryID;
#JoinColumn(table = "categories", name = "category_name")
private String productCategoryName;
exception:
Caused by: org.postgresql.util.PSQLException: ERROR: column
product0_1_.product_id doesn't exist
Hint: There may have been a link to the "product0_.product_id" column
Position: 705
how can i map this entity on 3 tables?
upd: i don't want separate this entity, i need this for deserialize my json object too, just want reuse this entity on different operations.
example of json
{"productID":"1111111","productName":"Cool product","productPrice":"99.99","productVendorName":"Some store","productVendorID":"1337","productCategoryName":"Food","productCategoryID":"1"}
Since there are 3 separate tables, you would want to create three separate entity classes.
Also I'm assuming vendors and category tables will have one to many relation to product.
Try below code:
Product:
#Entity
public class Product {
#Id
private int productId;
private String productName;
private BigDecimal productPrice;
private String productVendorName;
private String productCategoryName;
#ManyToOne
#JoinColumn(name = "productCategoryId")
private Category category;
#ManyToOne
#JoinColumn(name = "productVendorId")
private Vendors vendor;
}
Category:
#Entity
public class Category {
#Id
private Integer categoryId;
private String categoryName;
#OneToMany(mappedBy = "category", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
#NotEmpty
private List<Product> products = new ArrayList<>();
}
Vendors:
#Entity
public class Vendors {
#Id
private int vendorId;
private String vendorName;
#OneToMany(mappedBy = "vendor", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
#NotEmpty
private List<Product> products = new ArrayList<>();
}
Though, I would recommend using above approach, if you still want to have single entity class and 3 separate table with redudant data then use below:
#Entity
#SecondaryTables({ #SecondaryTable(name = "vendors"), #SecondaryTable(name = "categories") })
public class Product {
#Id
private int productId;
private String productName;
private BigDecimal productPrice;
private String productVendorName;
private String productCategoryName;
#Column(table = "categories")
private Integer categoryId;
#Column(table = "categories")
private String categoryName;
#Column(table = "vendors")
private int vendorId;
#Column(table = "vendors")
private String vendorName;
}
The id column of the main table will be present in all the 3 tables and used for joining them.
Sorry for poor wording of the question, just didn't know how to explane what i wanted.
All what i need just add #transient annotations for fields which i don't have in products table, and separate it like accepted answer was suggested.
#Entity
#Table(name = "products", schema = "store" )
#JsonIgnoreProperties(ignoreUnknown = true)
public class Product {
#Id
#Column(updatable = false, nullable = false, name = "product_id")
private int productId;
#Column(name = "product_name")
private String productName;
#Column(name = "product_price")
private BigDecimal productPrice;
#Transient
private String productVendorName;
#Transient
private String productCategoryName;
#Transient
private int vendorId;
#Transient
private int categoryId;
#ManyToOne
#JoinColumn(name = "product_category_id")
private Category category;
#ManyToOne
#JoinColumn(name = "product_vendor_id")
private Vendor vendor;
}
for vendors table entity
#Entity
#Table(name = "vendors", schema = "store")
public class Vendor {
#Id
#Column(name = "vendor_id")
private int vendorId;
#Column(name = "vendor_name")
private String vendorName;
#OneToMany(mappedBy = "vendor", cascade = CascadeType.ALL, fetch = FetchType.LAZY,
orphanRemoval = true)
#NotNull
private List<Product> products = new ArrayList<>();
}
and for categories
#Entity
#Table(name = "categories", schema = "store")
public class Category {
#Id
#Column(name = "category_id")
private Integer categoryId;
#Column(name = "category_name")
private String categoryName;
#OneToMany(mappedBy = "category", cascade = CascadeType.ALL, fetch = FetchType.LAZY,
orphanRemoval = true)
#NotNull
private List<Product> products = new ArrayList<>();
}
Wanted to leave here full answer on my question, maybe someone will need it later
Just check some problems with toString. Use it only in Product.class and better make 2 versions for print json and jpa.
I am facing a hibernate problem in updainting the join table in one to many mapping with hibernate. Below are my two entity class and join table entity class.
ArticleCategoryMap.java
#Entity
#Table(name = "ARTICLECATEGORYMAP")
public class ArticleCategoryMap {
private static final long serialVersionUID = -5653708523600543988L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column ( name = "id")
Long id;
#ManyToOne(targetEntity = Article.class, fetch = FetchType.EAGER, optional = true, cascade = CascadeType.PERSIST)
#JoinColumn(name = "ARTICLE_ID", nullable = true, insertable = true, updatable = true)
private Article article;
#ManyToOne(targetEntity = Category.class, fetch = FetchType.EAGER, optional = true, cascade = CascadeType.PERSIST)
#JoinColumn(name = "CATEGORY_ID", nullable = true, insertable = true, updatable = true)
private Category category;
//setter and getter
}
Article.java
#Entity
#Table(name = "ARTICLE")
public class Article {
private long id;
private String title;
private String description;
private String keywords;
private String content;
#Id
#GeneratedValue
#Column(name = "ARTICLE_ID")
public long getId() {
return id;
}
//setter and getter
}
Category.java
#Entity
#Table(name = "CATEGORY")
public class Category {
private long id;
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
#JoinTable(
name = "ARTICLECATEGORYMAP",
joinColumns = #JoinColumn(name = "CATEGORY_ID"),
inverseJoinColumns = #JoinColumn(name = "ARTICLE_ID")
)
#CollectionId(
columns = #Column(name="id"),
type=#Type(type="long"),
generator = "sequence"
)
private Collection<Article> articles;
#Id
#GeneratedValue
#Column(name = "CATEGORY_ID")
public long getId() {
return id;
}
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
#JoinTable(
name = "ARTICLECATEGORYMAP",
joinColumns = #JoinColumn(name = "CATEGORY_ID"),
inverseJoinColumns = #JoinColumn(name = "ARTICLE_ID")
)
#CollectionId(
columns = #Column(name="id"),
type=#Type(type="long"),
generator = "sequence"
)
// setter an getter
}
Now suppose first time I have 2 elements in article table which is mapping to one entry of the category table. so the join table will look something like
Now due to some reason, I want to update the entry where the article entry will map to a new category ID. So the final DB should look like
So My problem Is how can I update this join table.
If you want one to many relationship (1 category have many articles and 1 article to 1 category) you dont need a join table.
The entity classes should look like that:
Category Entity:
Contains a Set of articles:
#Entity
#Table(name = "CATEGORY")
public class Category {
private long id;
private String name;
#OneToMany(mappedBy="category")
private Set<Article> articles;
......
}
Article Entity:
#Entity
#Table(name = "ARTICLE")
public class Article {
#ManyToOne
#JoinColumn(name="id", nullable=false)
private Category category;
private long id;
private String title;
private String description;
private String keywords;
private String content;
.......
}
For more details take a look at hibernate-one-to-many. Hope this helps.
Also move annotation from methods to fields. This:
private long id;
#Id
#GeneratedValue
#Column(name = "CATEGORY_ID")
public long getId() {
return id;
}
Should be:
#Id
#GeneratedValue
#Column(name = "CATEGORY_ID")
private long id;
public long getId() {
return id;
}
Many to many relationship:
At your database you have 3 tables:
CATEGORY
ARTICLE
ARTICLECATEGORYMAP (join table)
For many to many relationship entities would be:
Category Entity:
#Entity
#Table(name = "CATEGORY")
public class Category {
#Id
#GeneratedValue
#Column(name = "CATEGORY_ID")
private long id;
private String name;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(
name = "ARTICLECATEGORYMAP",
joinColumns = { #JoinColumn(name = "CATEGORY_ID") },
inverseJoinColumns = { #JoinColumn(name = "ARTICLE_ID") }
)
Set<Article > articles = new HashSet<>();
.....
}
Article Entity:
#Entity
#Table(name = "ARTICLE")
public class Article {
#Id
#GeneratedValue
#Column(name = "ARTICLE_ID")
private long id;
private String title;
private String description;
private String keywords;
private String content;
#ManyToMany(mappedBy = "articles")
private Set<Category> categories = new HashSet<>();
.......
}
For more info take a look at many-to-many ralationship