2

I am new to the world of DAO. I have 3 tables.

  • Consumer
  • Bill
  • Receipt

Consumer table contains following fields

  • consumer_id
  • consumer_name
  • address

Bill table contains

  • bill_number
  • bill_date
  • consumer_id
  • bill_amount

Receipt table contains

  • receipt_no
  • pay_date
  • paid_amount
  • consumer_id

Bill table has a many to one relationship with Consumer table, Receipt table also has a many to one relationship with Consumer table.

Currently I have created three classes

  1. Consumer
  2. Bill
  3. Receipt

and created DAOs for them like ConsumerDAO, BillDAO, ReceiptDAO. They contains basic CRUD operations.

Now I want a listing of a consumer involving data from these three tables. I am using a JOIN SQL query for the same. It is as follows:

SELECT c.consumer_id,
       c.consumer_name,
       c.address,
       r.receipt_no,
       r.pay_date,
       r.paid_amount,
       b.bill_date,
       b.bill_number,
       b.bill_amount
FROM consumer c
LEFT OUTER JOIN
  (SELECT r.consumer_id,
          r.pay_date,
          r.receipt_number,
          r.paid_amount,
          ROW_NUMBER() OVER (PARTITION BY r.consumer_id
                             ORDER BY r.pay_date) AS rank
   FROM receipt r) r ON (c.consumer_id = r.consumer_id
                         AND r.rank = 1)
LEFT OUTER JOIN
  (SELECT b.consumer_id,
          b.bill_number,
          b.bill_date,
          b.bill_amount,
          ROW_NUMBER() OVER (PARTITION BY b.consumer_id
                             ORDER BY b.bill_date) AS rank
   FROM bill b) b ON (c.consumer_id = b.consumer_id
                      AND b.rank = 1)";

I was wondering in which DAO I should place this query ? I thought to add a Bill field and a Receipt field in the Consumer class and add a getCurrentBillAndReceipt() method in the ConsumerDAO. Is it the right way to do ?

I read the following question:

how to create a DAO for join tables

and some more, but I was not able to get the idea.

Community
  • 1
  • 1
kaushik
  • 2,308
  • 6
  • 35
  • 50
  • Keep in mind that, while this is great for understanding the concept, there are ORM tools like Avaje Ebean that will make your life a lot easier. – nmagerko Jul 24 '14 at 02:16
  • Also: would you be able to elucidate the difference between a bill and a receipt? I think I know what you're going for, but I want to be clear. – nmagerko Jul 24 '14 at 02:21
  • @nmagerko, bill is something given to consumer so that he can know how much he should pay and receipt is something which stores the information regarding payments made by consumer. – kaushik Jul 24 '14 at 02:28
  • Alright, cool. Since you have a many to one relationship of your bills and receipts with respect to a consumer in the Consumers table, I would suggest that you join all of your consumer's Receipts into a `Set` in the Consumer class, and all of his/her Bills into a `Set` in the same class (this would be done when your DAO retrieves a Consumer). Then, you can write a method in your Consumer DAO to go through the user's Bills and Receipts (no long, crazy SQL queries required) and return what you need – nmagerko Jul 24 '14 at 02:34
  • @nmagerko, as you have seen from my sql, I have to obtain information regarding consumer's latest bill and receipt and from using that SQL I can obtain that information in a single operation. As per your answer I have to make multiple SQL queries for the result I needed. Isn't it ? – kaushik Jul 24 '14 at 02:44
  • I think it should go in ConsumerDAO – Leo Jul 24 '14 at 03:15

1 Answers1

5

Instead of trying to make a query like this every time you need access to the most recent Bill/Receipt of each of your consumers, what if your Consumer POJO became the following:

public class Consumer {
    private Integer consumerId;
    private String consumerName;
    private String address;
    // join data into these variables
    private Set<Bill> bills = new Set<Bill>(0);
    private Set<Receipt> recipts = new Set<Receipt>(0);

    // add constructor and getter/setter methods here
}

Then, in your ConsumerDAO, your find methods could have the following logic:

public class ConsumerDAO {
    /*
     * Find a consumer without any transaction data JOINed in
     */
    public Consumer find(Integer consumerId){
        // create a new Consumer object
        // run SQL query to populate consumerId, consumerName, and address fields of new Consumer object
        // return new Consumer object
    }

    /*
     * Find a consumer with all transaction data JOINed in
     */
    public Consumer findWithTransactionData(Integer consumerId){
        // create new consumer object
        // run a query to get the the basic fields of the Consumer POJO, that also uses
        // JOINs to get all of the consumer's Bills and Receipts; store all of the latter
        // in the Consumer object's Sets
        // return consumer object
    }

    /*** Note that the following two methods could even go in the Consumer class at this point ***/
    public Bill getMostRecentBill(Consumer consumer){
        // iterate through the consumer's bills, and return the most recent one
    }

    public Receipt getMostRecentReceipt(Consumer consumer){
       // iterate through the consumer's receipts, and return the most recent one
    }
}

Is this what you're trying to do? I think it would make the most sense to put the "find most recent" methods in the Consumer class itself, because you then wouldn't have to pass anything to the method as a parameter; you could just call getMostRecentBill() on the Consumer object that you get from findWithTransactionData(Integer) if you wanted to. This is generally considered to be a poor practice, though, because the POJO is supposed to be as "dumb" as possible. Thus, how you want to handle that is up to you.

nmagerko
  • 6,586
  • 12
  • 46
  • 71
  • I understood what you said, but I have make more than one SQL queries to DB and have to collect more data than I have to . Won't it reduce performance ? – kaushik Jul 24 '14 at 03:11
  • 1
    See my edit. You will indeed want to have one SQL query when you call findWithTransactionData(). Then, you will have all of the Consumer's bills and receipts without having to hit the database every time you need to get the most recent bill/receipt. The latter part is where your performance gets a boost. – nmagerko Jul 24 '14 at 03:20
  • You might even want to add findWithBills() and findWithReceipts(), in which you only JOIN in the bills and receipts data, respectively, thereby limiting the data that you pull back. Elsewhere in your code, you call the "find" method that best suits your needs – nmagerko Jul 24 '14 at 03:22
  • I suppose I'll end by saying: the query you posted (or some form of it) belongs in the ConsumerDAO. Whether or not you want to JOIN in all of the data when you create the Consumer object or have a method in the DAO that will get the data for you as you need it is really dependent on how often you need to use that data per user. My solution works best if you need to manipulate Bills/Receipts for a user often – nmagerko Jul 24 '14 at 03:43
  • @kaushik hope that helped :) – nmagerko Mar 31 '16 at 16:55