Sequence in inheritance with hibernate annotation and oracle - oracle

I have an inheritance
Abstract class A:
#MappedSuperclass
public abstract class A {
public Integer id;
#Id
#Column(name = "ID", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
}
Subclass B, that uses a sequence:
#Entity
#Table(name = "B")
public class B
extends A {
private String descripction;
#Override
#SequenceGenerator(name = "SEQ_TRANSACTIONID", sequenceName = "SEQ_TRANSACTION", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_TRANSACTIONID")
public Integer getId() {
return id;
}
#Column(name = "DESCRIPTION", nullable = false)
public String getDescripction() {
return descripction;
}
public void setDescripction(String descripction) {
this.descripction = descripction;
}
}
And subclass C, that does not need a sequence:
public class C extends A {
}
The class B needs to generate a sequence but the class C doesn't.
I run the proyect with "hibernate.hbm2ddl.auto" in "create-drop". But SEQ_TRANSACTIONID is never created.
I've built this test so you can reproduce the error.
Help me please.....
Thanks in advance.

Related

Custom name for JPA #JoinColumn

A FailedDeliveryOrder class has a field with the type of DeliveryOrder class, while the DeliveryOrder class has a field with the type of List of ProductDes class. The DeliveryOrder field will be embedded in the same table as FailedDeliveryOrder.
How can I specify a custom name for the table of the List of ProductDes ?
FailedDeliveryOrder.java
#Table(name = "FailedDeliveryOrder")
#Entity
public class FailedDeliveryOrder {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Embedded
private DeliveryOrder deliveryOrder;
public FailedDeliveryOrder() {
}
public FailedDeliveryOrder(DeliveryOrder deliveryOrder) {
this.deliveryOrder = deliveryOrder;
}
//setter and getter
}
DeliveryOrder.java
public class DeliveryOrder {
#Entity
public static class ProductDes {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
public Product() {}
// setter and getter
}
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
#JoinColumn(
name = "DeliveryOrder_ID",
nullable = false
)
#OrderColumn(
name = "ProductDes_Position",
nullable = false
)
private List<ProductDes> product_descriptions = new ArrayList<Product>();
public DeliveryOrder() {
}
public DeliveryOrder(List<ProductDes> products) {
this.setProduct_descriptions(products);
}
public List<ProductDes> getProduct_descriptions() {
return product_descriptions;
}
public void setProduct_descriptions(List<ProductDes> product_descriptions) {
this.product_descriptions = product_descriptions;
}
}
Instead of autogenerated name.

Many to One Relationship with #IdClass

Using Spring Data JPA & Hibernate, I am saving an object Company, that has 0 to Many AccountMapping. The AccountMappings Primary Key is a composite of a String accountNumber and the Company Primary Key. When I save a new company the COMP_NUM from the Company Object is not set into the AccountMapping object. When I use long companyNumber it is zero, and Long it is NUM. Hibernate is executing the insert statement first, but how to get it to set the primary key from company into child object ?
#Entity
#Table(name = "COMPANY")
public class Company implements Serializable {
#Id
#Column(name = "COMP_NUM")
#SequenceGenerator(name = "comp_num_seq", sequenceName = "comp_num_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "comp_num_seq")
private long number;
#OneToMany(mappedBy = "companyNumber", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<AccountMapping> accountMappings;
public Company() {
super();
}
public long getNumber() {
return this.number;
}
public void setNumber(long id) {
this.number = id;
}
public List<AccountMapping> getAccountMappings() {
return accountMappings;
}
public void setAccountMappings(List<AccountMapping> accountMappings) {
this.accountMappings = accountMappings;
}
}
#Entity
#IdClass(value = AccountMappingPK.class)
#Table(name = "ACCOUNT_MAPPING")
public class AccountMapping implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ACCNT_NUM")
private String accountNumber;
#Id
#Column(name = "COMP_NUM")
private Long companyNumber;
#Column(name = "IS_PRIMARY")
private Boolean isPrimary;
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public Long getCompanyNumber() {
return companyNumber;
}
public void setCompanyNumber(Long companyNumber) {
this.companyNumber = companyNumber;
}
public Boolean getIsPrimary() {
return isPrimary;
}
public void setIsPrimary(Boolean isPrimary) {
this.isPrimary = isPrimary;
}
}
public class AccountMapping implements Serializable {
#Column(name = "EA_ACCNT_NUM", nullable = false)
private String accountNumber;
#Column(name = "COMP_NUM", nullable = false)
private Long companyNumber;
public AccountMapping() {
// default constructor
}
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNum(String accountNumber) {
this.accountNumber = accountNumber;
}
public Long getCompanyNumber() {
return companyNumber;
}
public void setCompanyNumber(Long companyNumber) {
this.companyNumber = companyNumber;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof AccountMappingPK) {
AccountMappingPK accntPk = (AccountMappingPK) obj;
if (!(accountNumber.equals(accntPk.getAccountNumber()))) {
return false;
}
if (!(accntPk.getCompanyNumber() == (companyNumber))) {
return false;
}
return true;
}
return false;
}
#Override
public int hashCode() {
int hash = (accountNumber == null ? 1 : accountNumber.hashCode());
return (int) (hash * companyNumber);
}
}
#Entity
#IdClass(value = AccountMappingPK.class)
#Table(name = "ACCOUNT_MAPPING")
public class AccountMapping implements Serializable {
#Id
#Column(name = "ACCNT_NUM")
private String accountNumber;
#Id
#ManyToOne
#JoinColumn(name = "COMP_NUM")
private Company company;
...
}
// No annotations in this class
public class AccountMappingPK implements Serializable {
private String accountNumber;
private Company company;
...
// All the getter/setter, constructors, and so on ...
}
The Hibernate ORM documentation has more details about mapping with #IdClass: See Example 134. IdClass with #ManyToOne

Why is my json returned from the controller with empty fields?

I am using the debugger in IntelliJ and right before the point of returning the result, the array is perfectly fine, as you can see here
But for some reason, the response in the browser looks like this
I don't understand why the fields are invisible.
This is what my 2 models look like:
Municipality:
#Entity
public class Municipality {
#Id
#JsonIgnore
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
String name;
}
Prediction
#Entity
public class Prediction {
#Id
#JsonIgnore
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
LocalDateTime tsPredictionMade;
LocalDateTime tsPredictionFor;
float pm10;
float pm25;
#ManyToOne
#OnDelete(action = OnDeleteAction.CASCADE)
Municipality municipality;
}
And this is my controller:
#RestController
#RequestMapping("/predict")
public class PredictionController {
private MunicipalityService municipalityService;
private PredictionService predictionService;
#Autowired
public PredictionController(MunicipalityService municipalityService, PredictionService predictionService) {
this.municipalityService = municipalityService;
this.predictionService = predictionService;
}
#GetMapping
public List<Municipality> getPredictions(){
List<Municipality> result = municipalityService.getPredictions();
return result;
}
#GetMapping("/{municipality}")
public List<Prediction> getPredictionsForMunicipality(#PathVariable("municipality") String name){
List<Prediction> result = predictionService.getPredictions(name);
return result;
}
}
The rest of the app (service and persistence layer) is pretty standard.
What is the reason for this?
You will need the getters and setters for your models. The Jackson library needs it for accessing its fields when converting the models into JSON, differently from JPA when converting the resultSet into models. Here is the code:
Prediction
#Entity
public class Municipality {
#Id
#JsonIgnore
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public LocalDateTime getTsPredictionMade() {
return tsPredictionMade;
}
public void setTsPredictionMade(LocalDateTime tsPredictionMade) {
this.tsPredictionMade = tsPredictionMade;
}
public LocalDateTime getTsPredictionFor() {
return tsPredictionFor;
}
public void setTsPredictionFor(LocalDateTime tsPredictionFor) {
this.tsPredictionFor = tsPredictionFor;
}
public float getPm10() {
return pm10;
}
public void setPm10(float pm10) {
this.pm10 = pm10;
}
public float getPm25() {
return pm25;
}
public void setPm25(float pm25) {
this.pm25 = pm25;
}
public Municipality getMunicipality() {
return municipality;
}
public void setMunicipality(Municipality municipality) {
this.municipality = municipality;
}
}
Municipality
#Entity
public class Municipality {
#Id
#JsonIgnore
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
You need getters and setter for each field that you want to expose.
You can use #Data from lombok project to avoid boilerplate code.
https://projectlombok.org/

Spring JPA EntityGraph fetches all lazy loaded properties

I've worked with Spring and Hibernate. Now having a look at Spring Data JPA (2.0.3) with JPA 2.2
AgencyTicketType
#Entity
#Table(name = "agency_ticket_type", catalog = "test")
public class AgencyTicketType implements java.io.Serializable {
private Long id;
private String name;
private Agency agency;
private Set<AgencyTicketCategory> agencyTicketCategories = new HashSet<AgencyTicketCategory>(0);
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "name", nullable = false, length = 100)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "agency_id", nullable = false)
public Agency getAgency() {
return this.agency;
}
public void setAgency(Agency agency) {
this.agency = agency;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "agencyTicketType")
public Set<AgencyTicketCategory> getAgencyTicketCategories() {
return this.agencyTicketCategories;
}
public void setAgencyTicketCategories(Set<AgencyTicketCategory> agencyTicketCategories) {
this.agencyTicketCategories = agencyTicketCategories;
}
}
AgencyTicketCategory
#Entity
#Table(name = "agency_ticket_category", catalog = "waytest")
public class AgencyTicketCategory implements java.io.Serializable {
private Long id;
private AgencyTicketType agencyTicketType;
private String name;
private BigDecimal price;
private Set<TripTicket> tripTickets = new HashSet<TripTicket>(0);
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "agency_ticket_type_id", nullable = false)
public AgencyTicketType getAgencyTicketType() {
return this.agencyTicketType;
}
public void setAgencyTicketType(AgencyTicketType agencyTicketType) {
this.agencyTicketType = agencyTicketType;
}
#Column(name = "name", nullable = false, length = 100)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#Column(name = "price", nullable = false, precision = 8)
public BigDecimal getPrice() {
return this.price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "agencyTicketCategory")
public Set<TripTicket> getTripTickets() {
return this.tripTickets;
}
public void setTripTickets(Set<TripTicket> tripTickets) {
this.tripTickets = tripTickets;
}
}
Repository
public interface TicketTypeRepository extends JpaRepository<AgencyTicketType, Long> {
#EntityGraph(attributePaths={ "agencyTicketCategories" }, type=EntityGraphType.LOAD)
#Query("select type from AgencyTicketType type where type.agency.code=?1")
List<AgencyTicketType> findByAgency(String agencyCode);
}
Service
#Service
public class TicketServiceImpl implements TicketService {
#Autowired private TicketTypeRepository ticketType;
#Transactional(readOnly=true)
#Override
public List<AgencyTicketType> findByName(String code) {
return ticketType.findByAgency(code);
}
}
When debugged on Service, it seems, the query eagerly fetches all the lazy loaded properties - agency, agencyTicketCategories - and all their inner lazy loaded properties, which leads to JSON serilization error.
Need to fetch only these
AgencyTicketTypes [
{
id, name,
agencyTicketCategories [
{id,name,price},....
]
},.....
]
Can I do this with #EntityGraph? What I am missing?
Specifying lazy loading is only a hint for the JPA provider. Depending on the provider you use (Hibernate, EclipseLink etc.) it may be completely ignored and the dependencies may be eagerly fetched.
What you need to do is configure how your classes are mapped to json. Assuming you are using Jackson you may need to use annotations like #JsonIgnore or #JsonView. You may also map your class that only has the fields you need.
You can use Jackson annotations #JsonBackReference/#JsonManagedReference. They address problem of infinite recursion with bidirectional links in object model. As far as I understand it is your case.
See http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion for more information.
One thing to point is that debugging while the transaction is open (touching the collection) will cause it to be loaded even if at real time it doesn't .. the other thing is that as #Apokralipsa mentioned , LAZY loading is just a hint that can be totally ignored and should never be relied upon whatever technique you are using

(Hibernate) Can't add entity with many-to-many relationship

Basically, my goal is to have product and factory entity where relationship is many-to-many.
Factory must have some product, while product is not necessary associated with a factory. The problem is that when I try to add Product entity I get this error.
Caused by: org.hsqldb.HsqlException: integrity constraint violation: NOT NULL check constraint; SYS_CT_10103 table: PRODUCT column: FACT_ID
This is my Application class. I want to be able to save product to repository without giving it factory list but I got that error, so I tried adding what's in the comment but the same error remains.
#SpringBootApplication
public class Application implements CommandLineRunner {
#Autowired
private ProductRepo prodRepo;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
#Transactional
public void run(String... strings) throws Exception {
Product one = new Product();
/*
List<Product> productList= new ArrayList<Product>();
productList.add(one);
SomeFactory factory_one = new SomeaFactory("one", productList);
List<Factory> factoryList = new ArrayList<Factory>();
factoryList.add(factory_one);
one.setFactoryList(factoryList);
*/
prodRepo.save(one);
}
Product.java
#Entity
#Table(name="PRODUCT")
public class Product {
private int id;
private List<Factory> factoryList = null;
public Product() {}
#Id
#Column(name = "PROD_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() { return id; }
public void setId(int id) { this.id = id; }
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "productList", targetEntity = Factory.class)
public List<Factory> getFactoryList() {
return factoryList;
}
public void setFactoryList(List<Factory> f) {
this.factoryList = f;
}
}
SomeFactory.java
#Entity
#Table(name ="SOME_FACT")
public class SomeFactory extends Factory {
private String name;
private List<Product> productList;
public SomeFactory() {}
public SomeFactory(String name, List<Product> products) {
this.name = name;
this.productList = products;
}
#Column(name = "FACT_NAME", nullable = false)
public String getName() { return name; }
public void setName(String name) { this.name = name; }
#ManyToMany
#JoinTable(name = "PRODUCT",
joinColumns = #JoinColumn(name = "FACT_ID", nullable = true),
inverseJoinColumns = #JoinColumn(name = "PROD_ID", nullable = false))
public List<Product> getProductList() {
return productList;
}
public void setProductList(List<Product> products) {
this.productList = products;
}
}
Factory.java
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Factory {
int id;
public Factory() {}
#Id
#Column(name="FACT_ID")
#GeneratedValue(strategy = GenerationType.TABLE)
int getId() { return id; }
void setId(int id) { this.id = id; }
}

Resources