3

我使用 Spring JDBC 将数据从数据库加载到业务模型实体中。我的 DAO 接口由扩展 JdbcDaoSupport 类的类实现,这些类负责使用 RowMapper 类创建实体。然后我有一个外观类,它包含所有 DAO 接口并充当我的模型类(业务逻辑类)请求业务实体的网关。由于没有延迟加载,所有业务实体数据都会立即加载。这对于大多数情况来说都很好,但在某些情况下,我确实想懒惰地从数据库中加载数据。

例如,我从数据库中获取所有订单,并且希望仅在日期满足特定条件(业务逻辑)时才加载订单详细信息。这是我设计的一个简单示例。我正在寻找改进设计的方法,以便在需要时支持延迟加载订单明细数据。您可以在业务逻辑类中看到,ProcessOrder 方法仅在 Order Date 为 Today 时才需要 Order 详细信息,否则不关心详细信息。但是,当通过外观类查询 Order 时,我的 DAO 会加载所有 Order Details。

我知道一种方法是在 DAO 和 Facade 类中公开 GetOrderDetails 方法,并允许业务逻辑类在需要时加载它。但是,它对我不起作用。我刚刚在这里提到了一个非常简单的案例,但是可能存在业务对象被传递到另一个转换层的复杂场景,我不希望这些层负责加载数据的惰性部分。

此外,另一种可能性是使用像 Hibernate 这样的 ORM 工具。但是,在我的应用程序中,这种情况可能仅适用于极少数地方,并且感觉使用 ORM 工具来实现这种行为是一种矫枉过正。

我不是在寻找任何超级花哨的东西,只是一个简单的设计来让我的特殊情况发生这种情况。感谢您的任何帮助/建议。

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
         }
      }
   }
}
4

3 回答 3

2

延迟获取背后的主要思想是定义如何获取数据而不是自己获取数据,这意味着order.getOrderDetails()调用的时间正是应该触发查询的时间。实现这一点的一种方法是通过在这种情况下getOrderDetails()扩展模型来装饰方法OrderRowMapper,对于您的示例,这看起来像这样

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;
        }

    }
}


所以你的商务舱现在会触发查询

// 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
         }
      }
   }
}
于 2019-11-01T09:05:46.040 回答
1

JPA 执行此操作的方式是执行另一个查询以获取满足该条件的每个订单的每个 orderDetails 实体。

它会在您在代码中调用它的那一刻进行获取。

order.getOrderDetails()  

因此,如果您要实现它,为什么不只做 JPA hibernate 所做的事情。

于 2017-12-24T19:22:43.543 回答
-1

根据我能理解你的问题,这是我的回复。

您想在 Order 对象中延迟加载 Order Details。为此,您必须LAZY=true在映射文件中设置您的订单详细信息集合,或者fetch=FetchType.LAZY如果您正在使用注释。

现在,当您查询 Order 对象时,直到需要时才会加载 Order 详细信息。

现在由于在 DAO 类中执行 getOrder 后会话将关闭,因此您将无法在业务层使用延迟加载的对象。为此,在返回对象之前在您的 DAO 方法中执行以下操作

Hibernate.initialize(order.getOrderDetails());

我希望我回答了你的问题。

于 2012-11-05T18:36:30.177 回答