我使用 Spring JDBC 将数据从数据库加载到业务模型实体中。我的 DAO 接口(interface)由扩展 JdbcDaoSupport 类的类实现,这些类负责使用 RowMapper 类创建实体。 然后我有一个外观类,它包含所有 DAO 接口(interface)并充当请求业务实体的模型类(业务逻辑类)的网关。因为没有延迟加载,所有业务实体数据都是一次性加载的。这对大多数情况都很好,但在某些情况下我确实想从数据库中延迟加载数据。
例如,我从数据库中获取所有订单,并希望仅在日期满足特定条件(业务逻辑)时加载订单详细信息。这是我设计的一个简单示例。我正在寻找改进设计的方法,以便在需要时支持延迟加载订单详细信息数据。 您可以在业务逻辑类中看到,ProcessOrder 方法仅在订单日期为今天时才需要订单详细信息,否则不关心详细信息。但是,当通过外观类查询 Order 时,我的 DAO 加载了所有的 Order Details。
我理解的一种方法是在 DAO 和 Facade 类中公开 GetOrderDetails 方法,并允许业务逻辑类在需要时加载它。但是,它对我不起作用。我刚刚在这里提到了一个非常简单的案例,但可能存在业务对象被传递到另一个转换层的复杂场景,我不希望这些层负责加载数据的惰性部分。
此外,另一种可能性是使用 Hibernate 之类的 ORM 工具。然而,在我的应用程序中,这种情况可能只适用于极少数地方,并且感觉使用 ORM 工具来实现这种行为是一种矫枉过正。
我不是在寻找任何 super 花哨的东西,只是一个简单的设计来实现我的特殊情况。感谢您提供任何帮助/建议。
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
}
}
}
}
最佳答案
延迟获取背后的主要思想是定义如何获取数据而不是自己获取数据,这意味着当 order.getOrderDetails()
被调用时,正是应该触发查询的时间.实现这一点的一种方法是通过在本例中扩展 OrderRowMapper
中的模型来装饰 getOrderDetails()
方法,对于您的示例,它看起来像这样
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
}
}
}
}
关于java - 没有任何 ORM 的延迟加载/初始化设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13237863/