Address Entity in multiple Entities without specifying it - java

i am currently building an Application with Spring and i have a Question there:
I want to have an Entity Address which looks like this:
#Entity(name = "Address")
#Table(name = "address")
#EntityListeners(AuditingEntityListener.class)
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "city")
private String city;
#Column(name = "country")
private String country;
#Column(name = "postalcode")
private String postalCode;
#Column(name = "state")
private String state;
#Column(name = "street")
private String street;
public Address() {
}
}
I want to use this Address Entity in multiple Entities, for example in the User or Order Entity. Later, i will like to have many Entities which need an Address. But i don't want to specify each Relation in the Address Entity, otherwise it will get to complex. Is it possible to have a Link from the User to the Address with only specifying this Link in the User Entity?
My User Entity looks something like this:
#Entity(name = "User")
#Table(name = "User")
#EntityListeners(AuditingEntityListener.class)
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "username")
private String userName;
#OneToOne(
mappedBy = "address",
orphanRemoval = true,
cascade = {
CascadeType.PERSIST,
CascadeType.REMOVE
}
)
private Address billingAddress;
public User() {
}
}

Yes, it is possible, but you don't actually need mappedBy property, otherwise you are telling JPA to search for a address property in the other side of the relationship (that you actually want to be unidirectional):
#Entity(name = "User")
#Table(name = "User")
#EntityListeners(AuditingEntityListener.class)
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "username")
private String userName;
#OneToOne(
orphanRemoval = true,
cascade = { CascadeType.PERSIST, CascadeType.REMOVE }
)
private Address billingAddress;
public User() {
}
}
You can read more about this in the following online resources:
https://docs.oracle.com/javaee/6/api/javax/persistence/OneToOne.html
https://www.baeldung.com/jpa-one-to-one
https://javabydeveloper.com/one-one-unidirectional-association/

Related

Insert data to multiple tables in spring jpa

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> {
}

In case of one to one mapping in Java springboot with JPA, I am getting null value

I have two entities like below:
users:
public class User implements Serializable {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private Long userId;
#Column(nullable = false)
private String userName;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
#JoinColumn(name="userId", referencedColumnName = "userId")
private Address address;
}
Address:
public class Address {
#Id #GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long addressId;
private String streetName;
private Long userId;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "userId", referencedColumnName="userId", insertable = false, updatable = false, nullable = false)
private User user;
}
I am doing userRepository.save(user); with user object as follows:
{
"userName" : "test",
"Address" : {
"streetName" : "street"
}
}
but in Address table, userId is coming as NULL even though there is a forign key relationship is there and when i am getting user entity Address is coming as NULL Can anyone please let me know where i am doing the mistake.
Thanks in advance.
If I changed the above code like this:
User.java
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "addressId")
private Address address;
Address.java
#OneToOne(mappedBy = "user")
private User user;
It worked fine.

SpringBoot JPA persist child of parent with nulls columns

I have strange problem. I have entity Company, Branch and Address.
Company has list of branch and every branch has address.
Im trying to persist branch with not exist before address entity, but Address is persist with nulls columns.
#Data
#Entity
#Indexed
#Table(name = "company")
public class Company {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
private String id;
#Field
#Column(name = "full_name", nullable = false, unique = true)
private String fullName;
#OneToMany(mappedBy = "company")
private Set<Branch> branches;
}
#Data
#Entity
#Table(name = "branch")
public class Branch {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column
private String phone;
#Column
private String email;
#OneToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
#ManyToOne
#JoinColumn(name = "company_id", referencedColumnName = "id")
private Company company;
}
#Entity
#Table(name = "address")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column
private String street;
#OneToOne(mappedBy = "address")
private Company company;
#OneToOne(mappedBy = "address")
private Branch branch;
}
Service ...
public Integer addBranch(BranchDto branchDto) {
Branch branch = modelMapper.map(branchDto, Branch.class);
Company company = companyRepository.getCompanyById(branchDto.getCompanyId());
branch.setCompany(company);
return branchRepository.save(branch).getId();
}
Dto...
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
public class BranchDto {
private Integer id;
private String phone;
private String email;
private AddressDto address;
private String companyId;
}
And that is effect...
Debugger...
What is the problem? Can you help me ?
You are using 'mappedBy' with the same id, It only works with the first one he find.
Try to change to other id.

spring data jpa find all by example nested collection property

I have two objects. The company that can have multiple nested addresses.
#Entity
#Data
#Table(name = "company")
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "phone")
private String phone;
#OneToMany(mappedBy = "company", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<Address> addresses;
}
Address class looks like this:
#Data
#Entity
#Table(name = "address")
#ToString(exclude = "company")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "postal_code")
private String postalCode;
#Column(name = "city")
private String city;
#Column(name = "street")
private String street;
#JsonIgnore
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "company_id")
private Company company;
}
I want somehow if it's possible, make a dynamic query that searches through the nested collection property. I made a search method which uses example matcher but the result is wrong. Every time I got everything from DB, not only company with address postal code that I'm looking for.
My search method looks like this:
#PostMapping("/search")
public List<Company> search(#RequestBody final Company company){
return companyRepository.findAll(Example.of(company,
ExampleMatcher.matchingAny()
.withIgnoreNullValues()
.withIgnorePaths("id")
.withStringMatcher(ExampleMatcher.StringMatcher.STARTING)));
}
In my database, I have two objects and this is the result of the search:
As you can see I received everything from DB instead of the only first company which address postal code starts with 1.
Hi you can use Specification<T>
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
For this you need to extend from interface JpaSpecificationExecutor:
public interface UserRepository extends JpaRepository<User> ,JpaSpecificationExecutor<User>{
}
And you also need to implement your custom Specification<T>
And then you can use repository.findAll(your impleneted Specification);
Spring docs :
https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaSpecificationExecutor.html
I think this is helpful.

MappingException hibernate mapping columns

I'm struggling with following issue:
Caused by: org.hibernate.MappingException: Foreign key
(FKj4uw5b6ekvxc2djohvon7lk7:bi_person_country_countries
[person_country_id])) must have same number of columns as the
referenced primary key (bi_person_country [country_id,person_id])
I created 4 models:
#Table(name = "bi_country")
#Entity
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name")
private String name;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "bi_person_country", joinColumns = #JoinColumn(name = "country_id"), inverseJoinColumns = #JoinColumn(name = "person_id"))
private Set<Person> persons;
Gender:
#Table(name = "bi_gender")
#Entity
public class Gender {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name")
private String name;
public Integer getId() {
return id;
}
Person:
#Table(name = "bi_person")
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "last_name")
private String lastName;
#Column(name = "additional_info")
private String additionalInfo;
#ManyToMany(cascade = CascadeType.ALL, mappedBy = "persons")
private Set<Country> countries;
#ManyToOne
private Gender gender;
PersonCountry:
#Table(name = "bi_person_country")
#Entity
public class PersonCountry {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
private Person person;
#ManyToMany
private List<Country> countries;
You dont need the PersonCountry class here as you are using #ManyToMany in both cases being Person and Country mappings.
If you have to keep it for some reason.. the linking table should not contain #OneToMany / #ManyToMany mappings, so you would have:
#ManyToOne
private Person person;
#ManyToOne
private Country country;
Keep in mind you may need to use #JoinColumn also if the database names are different than person_id and country_id.

Categories

Resources