Suppose you have a One-To-Many relation (header-detail) on Pembelian and PembelianDetail. If you are not Indonesian then to make it easier for you Pembelian is Purchase in English.
As usual we use @OneToMany and @ManyToOne annotation in our domain class. When writing those annotation it depends on our strategy, whether we will use 1 DAO+Cascade or 2 DAO to persist the data.
To better understanding my sentence here’s the code
1 DAO+Cascade
In this strategy we use just 1 DAO to persist both the header and the detail data which is Pembelian and PembelianDetail.
1 2 3 4 5 6 7 8 |
public class PembelianDaoImpl implements PembelianDao{ @Autowired SessionFactory sessionFactory; public void save(Pembelian pembelian) { sessionFactory.getCurrentSession().save(pembelian); } } |
This DAO is called in PembelianService with declarative transaction using @Transactional annotaion.
1 2 3 4 5 6 7 8 9 |
@Transactional public class PembelianServiceImpl implements PembelianService{ @Autowired PembelianDao pembelianDao; public void save(Pembelian pembelian){ pembelianDao.save(pembelian); } } |
So for you who might wondering how this strategy can save the detail data (PembelianDetail) since we didn’t create PembelianDetailDao here’s the trick. We use cascade property in @OneToMany so that every PenjualanDetail attached to Penjualan will be persisted automatically.
1 2 |
@OneToMany(mappedBy = "penjualan",cascade = CascadeType.ALL) List<PenjualanDetail> penjualanDetails=new ArrayList<PenjualanDetail>(); |
If we look into the generated SQL here’s what we will get
1 2 3 |
Hibernate: insert into PENJUALAN (tanggalTransaksi) values (?) Hibernate: insert into PENJUALAN_DETAIL (ID_PENJUALAN, produk) values (?, ?) Hibernate: insert into PENJUALAN_DETAIL (ID_PENJUALAN, produk) values (?, ?) |
Let’s see second strategy
2 DAO
In this strategy we write 2 DAO, PembelianDao and PembelianDetailDao.
1 2 3 4 5 6 7 8 |
public class PembelianDetailDaoImpl implements PembelianDetailDao{ @Autowired SessionFactory sessionFactory; public void save(PembelianDetail pembelianDetail) { sessionFactory.getCurrentSession().save(pembelianDetail); } } |
Next when we write PembelianDao we call PembelianDetailDao object inside this class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class PembelianDaoImpl implements PembelianDao{ @Autowired SessionFactory sessionFactory; @Autowired PembelianDetailDao pembelianDetailDao; public void save(Pembelian pembelian) { sessionFactory.getCurrentSession().save(pembelian); for(PembelianDetail detail:pembelian.getPembeliandetails()){ pembelianDetailDao.save(detail); } } } |
Since we didn’t use cascade property so every PembelianDetail attached in Pembelian must be persisted manually and individually in iteration way. And here’s the @OneToMany annotation
1 2 |
@OneToMany(mappedBy = "penjualan") List<PenjualanDetail> penjualanDetails=new ArrayList<PenjualanDetail>(); |
Again, we use PembelianService to call PembelianDao. The service is the same with the one we wrote above, there is no difference
1 2 3 4 5 6 7 8 9 |
@Transactional public class PembelianServiceImpl implements PembelianService{ @Autowired PembelianDao pembelianDao; public void save(Pembelian pembelian){ pembelianDao.save(pembelian); } } |
The SQL is same as well
1 2 3 |
Hibernate: insert into PENJUALAN (tanggalTransaksi) values (?) Hibernate: insert into PENJUALAN_DETAIL (ID_PENJUALAN, produk) values (?, ?) Hibernate: insert into PENJUALAN_DETAIL (ID_PENJUALAN, produk) values (?, ?) |
Conclusion
So both strategy is actually the same, we can infer it from the generated SQL. The important part is both persist strategy is in one transaction. 1 Dao+Cascade is in one transaction. 2 Dao is also in one transaction.