I'm using JPA with QueryDSL, In that scenario, I'm going to use JpaQuery Projections for fetching the only required data from DB. In my entity there is one OneToMany(List) Mapping But I'm not able to do projection on OneToMany mapping fields ie List. Please, anyone, tell me how we can get List by using projections in OneToMany mapping.
My entity class:-
public class Brand {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = COLUMN_BRAND_ID)
private int brandId;
#Column(name = COLUMN_BRAND_NAME, columnDefinition = "VARCHAR(255)", nullable = false, unique = true)
private String brandName;
#OneToOne(cascade = CascadeType.MERGE )
#JoinColumn(name = BRAND_LOGO_SMALL_FOREIGN_KEY)
private File brandLogoSmall;
#OneToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = BRAND_LOGO_LARGE_FOREIGN_KEY)
private File brandLogoLarge;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = COLUMN_CONTACT_PERSONS, nullable = true)
private List<BrandContactPerson> contactPersons;
#Column(name = COLUMN_OTHER_DETAILS, columnDefinition = "VARCHAR(255)", nullable = true)
private String otherDetails;
#Column(name = COLUMN_BRAND_STATUS, columnDefinition = "TINYINT(1) DEFAULT 1", nullable = false)
private int status;
#Column(name = BRAND_ADDED_BY_FOREIGN_KEY, nullable = true)
private int createdBy;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = COLUMN_BRAND_ADDED_ON, columnDefinition = "DATETIME", nullable = false)
private Date createdDate;
#Column(name = BRAND_MODIFIED_BY_FOREIGN_KEY, nullable = true)
private int updatedBy;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = COLUMN_BRAND_MODIFIED_ON, columnDefinition = "DATETIME", nullable = true)
private Date updatedDate;
#OneToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = COLUMN_CLASSIFICATION)
private Classification classification;
//Setter Getter
}
Service Impl Class
#Repository
public class BrandCustomRepositoryImpl implements BrandCustomRepository {
#Autowired
private BrandQueryDslRepository brandQueryDslRepository;
#Autowired
private EntityManager em;
#Override
public List<Brand> search(BrandSearchModel searchQuery) {
JPAQuery<Contract> query = new JPAQuery<>(em);
QBrand qBrand = QBrand.brand;
BooleanBuilder builder = new BooleanBuilder();
if (searchQuery.getPageNo() == null) {
searchQuery.setPageNo(0);
}
if (searchQuery.getPageSize() == null) {
searchQuery.setPageSize(UserSearchModel.DEFAULT_PAGE_SIZE);
}
prepareBrandSearchBuilder(builder, qBrand, searchQuery);
builder.and(qBrand.status.eq(Constant.ACTIVE));
List<Brand> brand1 = query.from(qBrand.brand).where(builder).offset(0).limit(20)
.select(Projections.bean(Brand.class, qBrand.brandName,qBrand.contactPersons))
.fetch();
return brand1;
}
This is the above example. Thanks in advance.
Related
I'm new on Java. I'm doing a HTTPDeleting with JpaRepository(DeleteById) and i recived the following error: ConstraingViolationException - FK_QUESTION_ID cannot be null.
#Entity
#Data
public class Question {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "QUESTION_ID")
private int id;
#Column(nullable = false)
private String title;
#Column(nullable = false)
private String description;
// QUESTION_ID => FOREING KEY COLUMN
#OneToMany(orphanRemoval = true, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "FK_QUESTION_ID")
private List<Answer> answers;
#Column(name = "LIKE_COUNT")
private int likeCount;
#Column(name = "INTEREST_AREA_ID", nullable = false)
private int interestAreaId;
#Column(name = "USER_ID", nullable = false)
private int userId;
#Column
private boolean active;
#Column(name = "CREATED_DT", nullable = false)
private Date createdDate;
}
#Entity
#Data
public class Answer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ANSWER_ID")
private int answerId;
#Column
private String description;
#Column(name = "LIKE_COUNT")
private int likeCount;
#Column(name = "USER_ID", nullable = false)
private int userId;
#Column
private boolean active;
#Column(name = "CREATED_DT", nullable = false)
private Date createdDate;
#Column(name = "FK_QUESTION_ID")
private int questionId;
}
I read that use CascadeType.Delete is not a good practice, so i used orphanRemoval but even in this way doesn't worked.
questionRepository.deleteById(id);
Your setup is almost correct, except you need to change couple of things here and there. Two important things are:
mappedBy = "question" in the parent entity (Question) targets question field of child entity (Answer)
#JoinColumn should be placed in the child class, through which you specify the column name FK_QUESTION_ID in the Answer table.
Hope, it helps.
#Entity
#Data
public class Question {
#OneToMany(mappedBy = "question", orphanRemoval = true, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Answer> answers;
}
#Entity
#Data
public class Answer {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "FK_QUESTION_ID", nullable = false)
private Question question;
// since you seem to use lombok, you can also use
// answer.getQuestion().getId() instead of this method
public int getQuestionId() {
return this.question.getId(); // question lazy fetching
}
}
I have an Bid entity defined as follows
#ToString
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
#Entity
#Table(name = "bid_details")
public class Bid {
private enum STATUS { INITIATED, DRAFT, COMPLETED }
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false, updatable = false)
private Integer id;
#Column(name = "govt_bid_id", nullable = false)
private String govtBidNumber;
#Temporal(TemporalType.DATE)
#Column(name = "release_date", nullable = false)
#JsonFormat(pattern = "dd-MM-yyyy")
private Date releaseDate;
#ManyToOne(optional = false)
#JoinColumn(name = "created_by", referencedColumnName = "id", updatable = false, nullable = false)
private User createdBy;
#Temporal(TemporalType.DATE)
#Column(name = "created_date", nullable = false)
#CreationTimestamp
private Date createdDate;
#ManyToOne
#JoinColumn(name = "updated_by", referencedColumnName = "id", updatable = false, nullable = false)
private User updatedBy;
#Enumerated(EnumType.STRING)
#Column(name = "status", nullable = false)
private STATUS status;
#Column(name = "avg_turnover")
private String avgTurnover;
#Convert(converter = StringListConverter.class)
#Column(name = "docs_required", columnDefinition = "json")
private List<String> docsRequired;
#Enumerated(EnumType.STRING)
#Column(name = "status", nullable = false)
private STATUS status;
}
and the corresponding columns are present in the bid_details tables. I have bid repository defined as follows:
public interface BidRepository extends JpaRepository<Bid, Integer> {
}
now when I try to access data by id using findById it is throwing No Value Present exception whereas if I try to access the data using findAllById I am getting correct result. Not able to figure out what's causing this weird behaviour.
Also, if I execute findAll first and then findById it is giving the correct result.
I am using spring-boot version 2.1.1
following is code where the entity is saved in the db
public Bid addBid(BidRequest bidRequest) {
User user = userRepository.findById(bidRequest.getCreatedBy()).get();
Bid bid = new Bid();
modelMapper.map(bidRequest, bid);
bid.setCreatedBy(user);
return bidRepository.save(bid);
}
BidRequest class is as follows:
#ToString
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
public class BidRequest {
private String govtBidNumber;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "yyyy-MM-dd")
private Date releaseDate;
#Temporal(TemporalType.DATE)
private Date endDate;
private int createdBy;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "yyyy-MM-dd")
private Date createdDate;
private int updatedBy;
private String status;
private List<String> docsRequired;
}
Have you tried orElse like this
findById(id).orElse(null);
Because findById returns an Optional object so you have to write orElse() after findById()
I am new to Hibernate. I have two tables Team(parent) and Product(child) with TEAM_ID column as a relationship, each team will have multiple products and each product will have single team. I have created entity classes with #OneToMany mapping in Team class and #ManyToOne in Product class.
I need to coverup below scenarios,
To save both product and team when team is new
Save only product if the team is already available
When i am trying to save product it tries to save team again throws constraint error.
Please help.
Team:
#Entity
#Table(name = "TEAM")
public class Team implements Serializable{
private static final long serialVersionUID = 5819170381583611288L;
#Id
#SequenceGenerator(name="teamIdSeq",sequenceName="team_id_seq",allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="teamIdSeq")
#Column(name="TEAM_ID", updatable = false, nullable = false, unique = true)
private int teamId;
#Column(name="NAME", nullable = false, unique = true)
private String teamName;
#Column(name="DESCRIPTION", nullable = false)
private String teamDesc;
#Column(name="CONTACTS", nullable = false)
private String contacts;
#Column(name="APPROVER_NAME", nullable = false)
private String approverName;
#Column(name="APPROVAL_STATUS", nullable = false)
private int approvalStatus;
#Temporal(TemporalType.DATE)
#Column(name="CREATED_ON", nullable = false)
private Date createdOn;
#Column(name="CREATED_BY", nullable = false)
private String createdBy;
#Temporal(TemporalType.DATE)
#Column(name="MODIFIED_ON", nullable = false)
private Date modifiedOn;
#Column(name="MODIFIED_BY", nullable = false)
private String modifiedBy;
#OneToMany(fetch = FetchType.LAZY, mappedBy="team", cascade = CascadeType.ALL)
private Set<Product> products;
//setters and getters
}
Product:
#Entity
#Table(name = "PRODUCT", uniqueConstraints = {#UniqueConstraint(columnNames = {"PRODUCT_ID", "TEAM_ID"})})
public class Product implements Serializable{
private static final long serialVersionUID = 5819170381583611288L;
#Id
#SequenceGenerator(name="productIdSeq", sequenceName="product_id_seq",allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="productIdSeq")
#Column(name="PRODUCT_ID", updatable = false, nullable = false)
private int productId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TEAM_ID")
private Team team;
#Column(name="NAME", nullable = false, unique = true)
private String productName;
#Column(name="DESCRIPTION", nullable = true)
private String productDesc;
#Column(name="APPROVER_NAME", nullable = false)
private String approverName;
#Column(name="APPROVAL_STATUS", nullable = false)
private int approvalStatus;
#Temporal(TemporalType.DATE)
#Column(name="CREATED_ON", nullable = false)
private Date createdOn;
#Column(name="CREATED_BY", nullable = false)
private String createdBy;
#Temporal(TemporalType.DATE)
#Column(name="MODIFIED_ON", nullable = false)
private Date modifiedOn;
#Column(name="MODIFIED_BY", nullable = false)
private String modifiedBy;
#OneToMany(fetch = FetchType.LAZY, mappedBy="product")
private Set<Form> forms;
//setters and getters
}
DAO:
#Repository
#EnableTransactionManagement
public class KMDBDAOImpl implements KMDBDAO {
#Autowired
private SessionFactory sessionFactory;
public void addTeam(Team team) {
Product product = new Product(team, "BMA" + Math.random(), "UI Tool", "test",
1, new Date(), "test", new Date(), "test");
Set<Product> products = new HashSet<Product>();
products.add(product);
team.setProducts(products);
if(getTeam(team.getTeamName()) != null) {
product.setTeam(getTeam(team.getTeamName()));
sessionFactory.getCurrentSession().saveOrUpdate(product);
} else {
sessionFactory.getCurrentSession().saveOrUpdate(team);
}
}
public Team getTeam(String teamName) {
Query query = sessionFactory.getCurrentSession().createQuery("from Team where teamName = :name");
query.setString("name", "teamName");
return (query.list().size() > 0 ? (Team) query.list().get(0) : null);
}
The only time that you should set Product list on Team is when Team is a new entity. So:
Set<Product> products = new HashSet<Product>();
products.add(product);
if(getTeam(team.getTeamName()) != null) {
product.setTeam(getTeam(team.getTeamName()));
sessionFactory.getCurrentSession().saveOrUpdate(product);
} else {
team.setProducts(products);
sessionFactory.getCurrentSession().saveOrUpdate(team);
}
i give you some example code for one to many relationship please go through it and let me kn if some problem .... i have 2 tables 1.product 2.sku my condition is , one product have many sku's ...
Product.java
#LazyCollection(LazyCollectionOption.FALSE)
#ElementCollection(targetClass=Product.class)
#OneToMany(mappedBy="product" , cascade=CascadeType.MERGE)
private List<Sku> listSkuOrders = new ArrayList<>();
Sku.java
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = PRODUCT_ID , nullable = false)
private Product product;
I have a question about "annotations" in hibernate.
I have a BaseEntity class and another class like state.java who extend
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler", "createdBy", "updatedBy" })
#MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private T id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CreatedBy", nullable = true)
private User createdBy;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "UpdatedBy", nullable = true)
private User updatedBy;
#Column(name = "createdDate", nullable = true, updatable = false)
private Date createdDate;
#Column(name = "UpdatedDate", nullable = true)
private Date updatedDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "subsite", nullable = true)
private Subsite subsite;
#Column(name = "ip", nullable = true)
private String ip;
#Entity
#Table(name="State")
public class State extends BaseEntity<Long> {
#Column(name = "state", nullable = true)
private String state;
#Column(name = "city", nullable = true)
private String city;
when program creat my tables in DataBase my table'design build like this:
How can I create a table so that the BaseEntity'fields place after state'fields in my Table
I have entity Ad:
#Entity
#NamedQueries({
#NamedQuery(name = "getAllAds",
query = "from Ad"),
#NamedQuery(name = "deleteById",
query = "delete from Ad where id = :id")
})
#FieldMatch(first = "initLanguage",second = "resultLanguage", message = "Languages must be different")
#Table(name = "AD_TEST")
public class Ad implements Serializable{
/**
* Version of this class in production
*/
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "standard", initialValue = 1)
#GeneratedValue(generator = "standard", strategy =GenerationType.SEQUENCE)
#Column(name = "AD_ID")
private long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "CLIENT",nullable = false)
private Client client;
#NotBlank
#Column(name = "AD_NAME", nullable = false)
private String name;
#NotBlank
#Column(name = "AD_DESC",nullable = false,length = 1000)
#Lob
#Size(min = 0, max = 1000)
private String description;
#Column(name = "AD_COUNTRY", nullable = false)
private String country;
#Column(name = "AD_CITY", nullable = false)
private String city;
#NotNull
/**
* Добавить проверку валидности даты
*/
#DateTimeFormat(iso = ISO.DATE,pattern = "dd.MM.yyyy")
#Column(name = "AD_END_DATE",nullable = false)
private LocalDate endDate;
#NotNull
#Column(name = "AD_INIT_LANGUAGE",nullable = false)
#Enumerated(EnumType.STRING)
private Language initLanguage;
#NotNull
#Column(name = "AD_RESULT_LANGUAGE",nullable = false)
#Enumerated(EnumType.STRING)
private Language resultLanguage;
#NotNull
#Column(name = "AD_TRANSLATE_TYPE",nullable = false)
#Enumerated(EnumType.STRING)
private TranslateType translateType;
#Lob
#Column(name = "AD_FILE")
private byte[] file;
#NotNull
#Column(name = "AD_COST",nullable = false,precision = 2)
private double cost;
#NotNull
#Column(name = "AD_CURRENCY",nullable = false)
#Enumerated(EnumType.STRING)
private Currency currency;
#Column(name = "AD_CREATING_DATE",nullable = false)
private LocalDateTime creationDateTime;
#Column(name = "AD_STATUS",nullable = false)
#Enumerated(EnumType.STRING)
private AdStatus status;
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToMany(fetch = FetchType.EAGER,orphanRemoval = true,mappedBy = "ad")
#Cascade(CascadeType.ALL)
private List<ResponsedAd> responsedAds = new ArrayList<>();
public Ad(){}
/*Getters and setters, hashCode and equals*/
Ad is element of collection in Client:
#Entity
#NamedQueries({
#NamedQuery(name = "clientByEmail",
query = "from Client client where client.email = :email")
})
#Table(name = "CLIENT_TEST")
#PrimaryKeyJoinColumn(name= "client_id")
public class Client extends User{
/**
* Version of this class in production
*/
private static final long serialVersionUID = 1L;
#OneToMany(fetch = FetchType.EAGER,orphanRemoval = true,mappedBy = "client")
#Cascade(CascadeType.ALL)
public List<Ad> ads = new ArrayList<>();
#OneToMany(fetch = FetchType.EAGER,orphanRemoval = true,mappedBy = "client")
#Cascade(CascadeType.ALL)
private List<ResponsedAd> responsedAds = new ArrayList<>();
public Client(){}
Ad.class and Client.class have collection of ResponseAd objects:
#Entity
#Table(name = "RESPONSED_AD_TEST")
#NamedQueries({
#NamedQuery(name = "responsedAdsByAd",query="from ResponsedAd where ad = :ad")
})
#Component
public class ResponsedAd {
#Id
#SequenceGenerator(name = "standard", initialValue = 1)
#GeneratedValue(generator = "standard", strategy =GenerationType.SEQUENCE)
private long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "AD",nullable = false)
private Ad ad;
#Column(nullable = false)
private LocalDateTime dateTimeOfResponse;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "CLIENT")
private Client client;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "TRANSLATOR",nullable = false)
private Translator translator;
#Column(nullable = false)
#Enumerated(EnumType.STRING)
private ResponsedAdStatus status;
public ResponsedAd(){}
I want that after deleting Ad object, all ResponseAd objects from collection were deleted too.
For this I have:
public void deleteById(long id){
Ad ad = get(id);
CopyOnWriteArrayList<ResponsedAd> list = new CopyOnWriteArrayList<>(ad.getResponsedAds());
list.forEach(rad->{
Translator translator = rad.getTranslator();
translator.removeResponsedAd(rad);
ad.removeResponsedAd(rad);
Client client = rad.getClient();
client.removeResponsedAd(rad);
});
Client client = ad.getClient();
client.removeAd(ad);
}
Say me please, how can I do this right? I have very a lot of relationships and when I try do this, I get error
HTTP Status 500 - Request processing failed; nested exception is
org.springframework.dao.InvalidDataAccessApiUsageException:
deleted object would be re-saved by cascade (remove deleted object from associations):
[ua.translate.model.ad.ResponsedAd#102]; nested exception is org.hibernate.ObjectDeletedException:
deleted object would be re-saved by cascade (remove deleted object from associations): [ua.translate.model.ad.ResponsedAd#102]
First of all,
You don't need to use #NotNull if you have nullable = false already declared in #Column(nullable = false).
Second,
What you're trying to do is doing operations in Cascade. Add this cascade = CascadeType.ALL or maybe cascade = CascadeType.REMOVE to your #ManyToOne tags and it should work.
Use this as a reference: JPA #ManyToOne with CascadeType.ALL
My Client object: Client client = rad.getClient(); have two responsedAd object in collection with the same id, therefore even after deleting this responsedAd object: client.removeResponsedAd(rad); client object has one more. And now main question is why this client have two objects with the same id.