在我的 java 应用程序中,我想为数据库操作实现抽象层。我不想将我的应用程序绑定(bind)到任何类型的数据库(实现可以是任意的:SQL、XML、基于文档、一堆丑陋的文本文件等)
实体之间有很多关系,大多数时候是一对多的关系。
更新和免责声明:虽然示例很简单,但它们只是整个更复杂模型的一部分,它们很可能不适合 ORM/SQL 模型(两者都是因为数据量很大:~由于数据的不同性质,当归一化为关系时有数十亿条记录)。我在这里问的是实现简单的关系,但这并不意味着它们构成了应用程序的唯一问题。
一个简化的例子如下:
public class Vehicle {
String mark;
String model;
String registrationId;
}
public class Depot {
String name;
String address;
}
这些实体中的每一个都有自己的 DAO 接口(interface):
public interface VehicleDAO {
List<Vehicle> getVehicles();
Vehicle getVehicleByRegistrationId(String registrationId);
}
public interface DepotDAO {
List<Depot> getDepots();
Depot getDepotByName(String name);
}
这些 DAO 也被简化了,只是为了展示一些为特定实体隔离的方法(通过其注册 ID 获取车辆我不需要知道任何关于其他实体的信息)。
现在有趣的部分来了。 Depot 和 Vehicle 之间的关系是一对多的。所以我必须在我的实体类和 DAO 方法中实现这种关系。
现在我有两种方法:
- 地点
List<Vehicle>
里面的属性(property)Depot
类并在我获取Depot
时填充它实例(具有可能的延迟获取改进)。这样 DAO 接口(interface)就不会改变。 - 为
Depot
引入特殊标识符和Vehicle
,以便实体类获得额外的整数属性int id;
我们向 DAO 添加一个方法List<Vehicle> getVehiclesForDepot(int depotId)
.可以通过为标识符而不是普通整数引入特殊类来增强这种方法。
也许还有其他方法?为实体之间的关系建模和设计 DAO 接口(interface)以保持数据库抽象易于使用且不绑定(bind)到任何类型的数据库的最佳方法是什么?我问的不一定是完整准确的解决方案,而是解决上述问题时的一些原则。
最佳答案
在您的示例中,您使用了本地化为 DAO 类型的方法,最好定义一组一致的 DAO 方法来涵盖这些功能,即
// load object of DAO type T
<T> load(id)
// load objects of DAO type T
List<T> load(List<id>)
// load all objects of DAO type T
List<T> find()
// load multiple objects of DAO type T
List<T> find(relation)
等等,如果你使用一致的id
输入(例如 long
)你可以定义一个 interface
涵盖您的基本方法。
要加载关系,您有几个选择,这最好取决于您对对象及其关系的使用:
- 制作
List<T>
数据持有者的一个属性并将其填充为load()
的一部分
这适用于少量关系,当相关实体与其他实体没有关系时。如果他们这样做,您将不得不部分加载它们以防止预先加载太多(您提到的延迟加载是一种策略。)
- 制作
List<T_id>
数据持有者的一个属性并将其填充为load()
的一部分
这适用于适量的关系,与 load(List<id>)
一起使用访问相关实体的方法。
对于大量数据,正如您提到的是您要解决的大部分问题,您可以进一步分离关系并使用 DAO 方法,例如:
// retrieve related entity id's for this DAO T
List<id> loadIds(T)
加载(外国)集id
用于与作为参数传递的数据持有者对象有关系的实体。然后,您的管理器/业务/服务层使用该 ID 列表来加载下一组实体,可能通过将偏移量传递到 ID 列表和要加载的实体数量来分块。
或者,您可以通过添加 DAO 方法来解耦有关关系的知识,以填充另一种 DAO 类型的数据持有者对象中的外部关系:
// fill entity relations for T2 to this DAO tyoe T
void fill(T2)
T::fill()
方法将在 T2
上使用 setter/getter 获取确定要加载的相关实体(或其 id
的)所需的数据,以及一个或多个 setter 将该信息存储在 T2
中数据持有者对象。
大多数这些 DAO 的加载方法会将关系数据集保留为 null
留待以后加载。这当然意味着他们的数据持有者对象 getter 必须能够处理 null
值(value)作为契约(Contract)的一部分。
关于java - DAO设计和数据结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8601327/