如何解决这个问题:当使用JPA持久化时,应用程序模型和引擎模型不匹配?
标题可能看起来很混乱,但用几句话来描述这个问题并不容易。让我解释一下情况: 我们有一个web应用程序项目和一个计算引擎项目。web应用程序收集用户输入并使用引擎生成一些结果,并向用户表示。用户输入、引擎输出和其他数据都将使用JPA持久化到DB 引擎输入和输出由树状结构中的对象组成,例如:如何解决这个问题:当使用JPA持久化时,应用程序模型和引擎模型不匹配?,jpa,model,presentation,mismatch,Jpa,Model,Presentation,Mismatch,标题可能看起来很混乱,但用几句话来描述这个问题并不容易。让我解释一下情况: 我们有一个web应用程序项目和一个计算引擎项目。web应用程序收集用户输入并使用引擎生成一些结果,并向用户表示。用户输入、引擎输出和其他数据都将使用JPA持久化到DB 引擎输入和输出由树状结构中的对象组成,例如: Class InputA { String attrA1; List<InputB> inputBs; } Class InputB { String attrB1; List&l
Class InputA {
String attrA1;
List<InputB> inputBs;
}
Class InputB {
String attrB1;
List<InputC> inputCs;
}
Class InputC {
String attrC1;
}
在JavaOO世界中,这是可行的,我们可以在InputA中存储InputBx的列表,并且由于继承,我们可以在InputBx中存储InputCx的列表
但是,当使用JPA持久化扩展对象时,我们遇到了麻烦
首先,它需要engine项目使它们的类成为JPA实体。发动机本身工作正常,它接受正确的输入并产生正确的输出。当另一个项目试图持久化模型时,强迫他们的模型成为JPA实体并不是件好事
其次,当使用InputA作为条目时,JPA不接受继承的对象。从JPA的角度来看,它只知道InputA包含一个InputB列表,不可能在InputA的对象中持久化/检索InputBx列表
在试图解决这一问题时,我们提出了两个想法,但没有一个让我们满意:
想法1:
使用组合而不是继承,因此我们仍然保留原始Input,其树结构包括InputB和InputUTC:
Class InputBx{
String attrBx1;
InputB inputB;
}
Class InputCx{
String attrCx1;
InputC inputC;
}
因此,可以顺利地检索原始输入对象树,并且需要使用树中的InputB和InputUTC对象作为引用来检索InputBx和InputCx对象
好的方面是,无论对原始输入类树的结构做了什么更改(例如更改属性名、在类中添加/删除属性),扩展类InputBx和InputCx及其属性都会自动同步
缺点是这种结构增加了对数据库的调用,并且该模型在应用程序后端和前端都不容易使用。每当我们需要InputB或InputUTC的相关信息时,我们都需要手动编码来搜索InputBx和InputCx的对应对象
想法2:
手动创建镜像类,以形成与原始输入类类似的结构。因此,我们创建了:
Class InputAx {
String attrA1;
List<InputBx> inputBs;
}
Class InputBx {
String attrB1;
List<InputCx> inputCs;
String attrBx1;
}
Class InputCx {
String attrC1;
String attrCx1;
}
我们可以使用它作为web应用程序的模型,也可以使用JPA实体。以下是我们可以得到的:
现在引擎项目可以自由设置,它不需要绑定到其他项目如何持久化这些输入/输出对象。引擎项目现在是独立的
JPA持久性工作非常流畅,不需要额外调用数据库
后端和前端UI只需使用此模型即可轻松获取原始输入对象和相关信息。当尝试使用引擎执行计算时,我们可以使用映射机制在原始对象和扩展对象之间进行转换
缺点也很明显:
类结构中存在重复,从OO的角度来看,这是不需要的
当将其视为减少数据库调用的DTO时,在本地传输中使用DTO时,可以将其称为反模式
结构不会自动与原始模型同步。因此,如果对原始模型进行了任何更改,我们也需要手动更新此模型。如果一些开发人员忘记了这样做,就会有一些不容易发现的缺陷
我正在寻找以下帮助:
是否存在任何现有的良好/最佳实践或模式来解决我们遇到的类似情况?或者我们应该避免的任何反模式?欢迎参考网络文章
如果可能的话,您能否从OO设计、持久性实践、您的经验等方面对想法1和想法2进行评论
我将非常感谢你的帮助。嗯,当事情如此抽象时,我很难想象你在做什么。你能告诉我你代表的是什么样的数据吗?尼尔,很高兴在这里见到你。我使用抽象类是因为我认为这类问题是泛型的。例如,可以是这样的映射:InputA=City,InputB=TravelAgent,InputUTC=TravelPlan,InputBx包含TravelAgent的流程说明,InputCx包含其他TravelPlan调整。引擎只需要InputA InputB和InputUTC中的信息,UI将显示所有信息,包括InputBx和InputCx中的信息。
Class InputAx {
String attrA1;
List<InputBx> inputBs;
}
Class InputBx {
String attrB1;
List<InputCx> inputCs;
String attrBx1;
}
Class InputCx {
String attrC1;
String attrCx1;
}