3

I use Spring JDBC to load the data from a DB into the business model entity. My DAO interfaces are implemented by the classes that extend the JdbcDaoSupport class, which are responsible to creating the entity using the RowMapper classes. Then I have a facade class, which holds all the DAO interfaces and acts as a gateway to my model class (business logic class) requesting the business entities. Since, there is no lazy loading, all business entity data are loaded at once. This is fine for most of the cases, but in some cases I do want to load the data from DB lazily.

For example, I get all the Orders from the DB and would like to load Order Details only if the date meets certain condition (business logic). Here is a simple example of my design. I am looking for ways to improve the design so I could support lazy loading of Order Detail data if needed. You can see in the Business logic class, the ProcessOrder method needs the Order details only if the Order Date is Today, else doen't care about the details. However, my DAO loads all the Order Details when querying for Order by the facade class.

I understand one way is to expose the GetOrderDetails method in DAO and Facade class and allow the business logic class to load it, when needed. But, it wouldn't work for me. I have just mentioned a very simple case here, but there could be complex scenarios where the business object is passed on to another transformation layer and I don't want these layers to be responsible for loading the lazy part of the data.

Also, another possibility is to use a ORM tool like Hibernate. However, in my application this case may be applicable only at very few places and feel using an ORM tool to achieve this behavior is an overkill.

I am not looking for anything super fancy, just a simple design to make this happen for my special cases. Thanks for any help/suggestions.

class Order // Simple POJO business entity
{
   int OrderID;
   Date OrderDate;
   Collection<OrderDetail> OrderDetails; // Need to load lazily
}

class OrderDetail //Simple POJO business entity
{
   Order order;
   int ItemID;
   double Cost;
   int Quantity;
}

// DAO Interface
interface OrderDAO
{
   Order getOrder(int aOrderID);
}

// Concrete DAO class
JdbcOrderDao extends JdbcDaoSupport implements OrderDao
{
   Order getOrder(int aOrderID)
   {
      Order order = getJdbcTemplate.query(....., new OrderRowMapper());
      populateOrderDetails(order);
      return order;
   }

   private PopulateOrderDetails(Order aOrder)
   {
      //Query the DB and fill the Order details data.
   }

   private class OrderRowMapper implements ParameterizedRowMapper<Order>
   {
      // Code implemented to create and return the business entity from the resultset;
   }
}

// Facade class that hides the DAO interface and exposes the business methods
ServiceFacade
{
   private OrderDAO orderDAO;

   public Order GetOrder(int aOrderID)
   {
      return orderDAO.getOrder(aOrderID);
   }
}

// Business Logic class
BusinessModelLoader
{
   List<Order> Orders = new ArrayList<Order>();
   LoadOrders()
   {
     for(Integer orderID : allOrderIDs)
       Orders.add(facade.getOrder(orderID));
   }

   ProcessOrders()
   {
      for(Order order: Orders)
      {
         if (order.OrderDate == Today)
         {
            List<OrderDetail> details = order.OrderDetails; // Need to perform lazy loading here automatically
            // Do something with details
         }
      }
   }
}
2
  • What is the exact problem are you facing in lazily loading the object? Commented Nov 5, 2012 at 18:21
  • I am looking as how I could accommodate lazy loading in my current design. Its more of a design problem. Commented Nov 5, 2012 at 18:23

3 Answers 3

3

The main idea behind lazy fetching is to define how to fetch the data instead of fetching it yourself, this means that when order.getOrderDetails() is called that is exactly when the query should be triggered. One way to achieve that is by decorating the getOrderDetails() method by extending the model in the OrderRowMapper in this case, for your example this would look like this

class Order // Simple POJO business entity
{
    int OrderID;
    Date OrderDate;
    Collection<OrderDetail> OrderDetails; // Need to load lazily

    public void setOrderDetails(Collection<OrderDetail> orderDetails) {
        this.OrderDetails = OrderDetails;
    }

    public Collection<OrderDetail> getOrderDetails() {
        return OrderDetails;
    }

}

class OrderDetail //Simple POJO business entity
{
    Order order;
    int ItemID;
    double Cost;
    int Quantity;
}

// DAO Interface
interface OrderDAO
{
    Order getOrder(int aOrderID);
}

// Concrete DAO class
class JdbcOrderDao extends JdbcDaoSupport implements OrderDao
{
    Order getOrder(int aOrderID)
    {
        Order order = getJdbcTemplate().queryForObject("...", new OrderRowMapper(this));
        return order;
    }

    public void populateOrderDetails(Order aOrder)
    {
        //Query the DB and retrieve the order details
    }

    private class OrderRowMapper implements RowMapper<Order>
    {
        private JdbcOrderDao dao;

        public OrderRowMapper(JdbcOrderDao dao) {
            this.dao = dao;
        }

        @Override
        public Order mapRow(ResultSet rs, int rowNum) throws SQLException {
            Order order = new Order() {
                @Override
                public Collection<OrderDetail> getOrderDetails() {
                    dao.populateOrderDetails(this);
                    return super.getOrderDetails();
                }
            };
            // set other fields
            return order;
        }

    }
}


So your business class will trigger the query now

// Business Logic class
class BusinessModelLoader
{
   List<Order> Orders = new ArrayList<Order>();
   LoadOrders()
   {
     for(Integer orderID : allOrderIDs)
       Orders.add(facade.getOrder(orderID));
   }

   ProcessOrders()
   {
      for(Order order: Orders)
      {
         if (order.OrderDate == Today)
         {
            Collection<OrderDetail> details = order.getOrderDetails(); // performs lazy loading here automatically
            // Do something with details
         }
      }
   }
}
Sign up to request clarification or add additional context in comments.

Comments

1

The way JPA would do that is perform another query to fetch each orderDetails entity for each order that meets that criteria.

It does the fetching the minute you call it in code.

order.getOrderDetails()  

So for you to implement it why dont you just do what JPA hibernate does.

Comments

-1

By what i could understand your question, here is my reply.

You want to lazily load the Order Details in your Order object. For that you have to set your Order Details collection as LAZY=true in your mapping file or fetch=FetchType.LAZY if you are using annotations.

Now when you query for Order object, Order details will not be loaded until needed.

Now since the session will be closed after executing the getOrder in DAO class, you will not be able to use the lazily loaded object in business layer. For that do the following in your DAO method before returning the object

Hibernate.initialize(order.getOrderDetails());

I hope I answered your question.

1 Comment

Anand, Thanks for your response. In my case, I am not using any ORM tools. The lazy loading is really needed for just couple of cases for me. Using an ORM tool for this, could be an overkill for my application.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.