所以基本上我正在检查hibernate的工作,以及评估ORMs JOOQ。 JPA或多或少是所有基于Java的ORM实现的主要事实标准。
我并不是说他们不是完美或不错,但我的问题就像我发现了很多问题并且在使用以下提供的各种选项时,我的问题是:
喜欢例如。 My Bean / POJO有近80列
在一个地方我只需要10列和另一个地方我需要我的Bean / POJO映射到的表的20列。现在在这种情况下,我必须创建2个单独的DTO包含选择字段,或者我必须在我的主映射Bean / POJO中创建两个不同的重载构造函数。
这是按照JPA,没有办法只使用getter settersof字段来初始化我的Bean / POJO。
这背后的想法是减少不必要的类,我们必须不必要地创建。
此外,如果我有这样的情况,从表中我必须获取近25种不同的组合,那么就JPA而言,我必须在一个Bean / POJO或25个不同的DTO(WTH)中创建25个不同的构造函数。
湾当我的Bean / Pojo的构造函数如下所示时,Hibernate失败
MyBean(String name, String email)
在选择的时候我会做什么
query.multiselect(new Selection[]{mappingBean.get("email"),mappingBean.get("name")});
它以错误的顺序初始化,这是根据我的类型地狱缺陷。 (课程开发人员确实有责任,但仍然是错误的)
现在,如果我在一个表上有25种不同脚本的不同组合,我必须为这些脚本编写25种不同的方法,因为Hibernate或JPS的标准API都有糟糕而复杂的脚本构建系统。
如果是JOOQ,它的所有java都是用脚本解释的。(WTH)
现在没有简单的API或ORM可以满足我发现的以下要求如果你能帮助我,我会很满意你。
我创建了一些代码,它作为对象传递给MY API应该能够做到的方法。
4.没有人能够正确支持复杂的脚本,如动态联合交叉点。
等等这个清单很长但是如果你可以帮助我至少一些合适的人可以帮助我...
编辑:
现在编辑JOOQ部分
我没有探索JOOQ的内部它也使用AST确定但我的问题是它跟随的模式可以check here
如果我看到普通的JDBC已经做了什么错误,如果我必须以Integer或String的形式从数据库获取我的数据或将个别数据类型作为单个字段获取,这个工具我的JDBC是给我的任何方式我必须在那里照顾在JDBC中用于类型安全,我必须使用JOOQ DSL。至少我期望像Hibernate Criteria API提供的结果中的Bean / POJO或者JPA提供的,它的不同之处在于它们也有它们的滞后。如果JOOQ我不知道,因为我已经看到的例子在其教程中找到了SQL类型代码。
现在让我们来看另一个例子(到目前为止我们已经探讨了你可以帮我弄清楚我可以通过Hibernate找到的一些问题,我试图通过它的社区加入,检查here和here(因为你已经感谢了)并引用了这些API作为灵感),
例如。 JOOQ的例子[![来自JOOQ的例子] [1]] [1]
现在,如果我们观察,我必须写1个sql或只有一组列选择,我最终使用它,但想象我必须在N没有地方使用不同列的相同表,然后我必须写N否脚本(这里的代码是可以互换的JOOQ SCRIPT检查图像是什么意思,tyour SQL和代码看起来互相模仿)JOOQ DSL,
所以我在下面分析了这一点:
在这里,我将通过创建N个方法来创建混乱因为我必须弄清楚4个列我必须使用方法X而对于5个列我必须使用方法Y,这将更加糟糕当你拥有100个开发人员的团队因为每个人都可能没有努力找到正确的方法,而是他/她在那里创建自己,这将创建冗余和重复的代码。
我也相信你不想在你的业务逻辑层中调用像DSL这样的脚本,因为你只需要基于什么原因,而“HOW&From WHERE”是ORM及其盟友的任务(这里我指的是使用DAO调用作为盟友或ORM的数据获取的DAO和Factory方法。
因此,对于任何选择,我只需要编写一个方法,例如。我们称之为工厂类中的List findData(SearchCriteria sc)(M将其称为工厂,因为它将具有来自DAO的方法和对象,并且使用DAO将提供Bean的List,因此它将成为使用ORM的数据库中的对象生成器类) 。
现在这个方法有责任在标准的基础上为我提供所需的输出,在这种情况下,无论我在业务层,我需要一组特定的数据,我可以创建搜索条件并将其传递给这个方法,这将给出我的Beans / POJO列表。
因此,我可能会根据业务逻辑层不同部分的要求创建搜索条件,无论N次数何时都无法获取数据,但至少我知道获取数据的责任仅限于我工厂类的一个方法。在我的业务层和我的ORM API之间是一种分隔符(例如你拿门),工厂事务将由ORM处理而不是由用户处理,或者我说开发人员本身。
希望你明白我的意思。
这些东西hibernate或JPA已经解决了一些但并不完全,因为他们的术语也是相同的,无论你需要使用标准构建器,业务层内的条件查询都不是一个好的代码结构。
编辑2:
卢卡斯,我明白了我的观点
public static ResultQuery<Record2<String, String>> actors(
Function<Actor, Condition> where
) {
return ctx.select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
.from(ACTOR)
.where(where.apply(ACTOR)));
}
在这里,ACTOR看起来像实际的表名和FIRST_NAME,因为它有任何标准,我们必须遵循某些代码实践,或者我必须自己设计它
比如A Bean / POJO / DTO,例如UserBean.java可以保存从DB获取的数据,因为它是Table USER的默认映射,我们可以使用using获取数据
ctx.select( *).from(UserBean.class) //I m not sure how do * but will figgure out that separately
因此,在这种情况下,理想情况下必须有标准映射器,例如在上面的例子中UserDAO.java,它将具有静态最终字符串形式的字段,其中包含表和表名的精确列名。
这可以被工厂用来在更广泛的层面调用,(它只是一个正确的代码结构的想法),
那么JOOQ是否列出了任何练习或模式建议?我刚才给出了解释。
它有许多表,这些表包含列,这些列在两个表之间提供了适当的关系,但没有在db级别应用任何外键关系。
现在在hibernate中的这种情况下,Join变得非常困难,我们必须处理包含交叉表数据映射和HQL或纯SQL的DTO的帮助。
我的想法是,如果我必须加入两个在db级别没有正确关系的实体,那么JOOQ是否有以下安排?
如果有UserBean和BankAccountBean,其中一个用户可以有多个银行帐户,
所以对于下面的脚本
Select A.USER_ID, A.USER_NAME, B.BANK_NAME, B.BANK_ACCT_TYPE, B.BANK_ACCT_NUMBER
FROM USER A LEFT JOIN USER_BANK_ACCOUNT B On A.USER_ID = B.USER_ID
现在在这种情况下,理想情况下,而不是创建一个单独的整个新Bean我的想法是,必须有UserBankAcctJoinBean应该能够处理此数据提取(这里必须考虑动态选择)
现在,如果我们谈论UserBankAcctJoinBean,它应该扩展UserBean(因为在我的连接中主表是User)所以默认情况下它会继承Users的所有属性,它应该包含UserBankAccountBean的引用变量,所以选择部分属于USER_BANK_ACCOUNT应通过反射在此参考上初始化
这里它与Hibernate不同,因为它允许具有辅助表的列表对象,这不是基本思想,因为hibernate在模式中的表之间包含适当的已建立的关系。
JOOQ有这种或类似的方式吗?
同样在hibernate源代码的情况下,它首先将数据从ResultSet加载到Object []然后使用字段的setter方法初始化Bean / POJO / DTO,所以这里如果你看到双延迟,而不是通过调用字段来直接初始化对象getter setter它首先将数据存储到Object数组然后从该数组加载到bean,最终创建每次获取行迭代两次。
这实际上是浪费资源,因为相同的任务迭代在同一组数据上两次不是一种有效的方法,
那么JOOQ如何在内部运作?是否使用getter setter直接将数据初始化为DTO,或者它的工作方式与Hibernate相似?
我会尝试回答你的jOOQ部分
如果我看到普通的JDBC已经做了什么错误,如果我必须以Integer或String的形式从数据库获取我的数据或将个别数据类型作为单个字段获取,这个工具我的JDBC是给我的任何方式我必须在那里照顾在JDBC中用于类型安全,我必须使用JOOQ DSL。至少我期望像Hibernate Criteria API提供的结果中的Bean / POJO或者JPA提供的,它的不同之处在于它们也有它们的滞后。如果JOOQ我不知道,因为我已经看到的例子在其教程中找到了SQL类型代码。
jOOQ可以将您的元组投射到任意“Beans / POJO”中。只需使用DefaultRecordMapper
。一个例子:
class DTO {
int a;
int b;
int c;
}
然后
List<DTO> dtos =
ctx.select(T.A, T.B)
.from(T)
.fetchInto(DTO.class);
如果我必须编写N没有不同的选择,那么我将编写一个类,它将在N中包装所有选择没有不同的方法,我需要在哪里,我只需要在我的业务逻辑层调用这些方法来获取数据(这是我在HQL,JPQL和JOOQ DSL(按图像)中看到的缺陷。
你没有发布任何图像,但从我如何理解你的问题,在上面的例子中,我重复使用DTO获取两列而不是3.没有必要为每个查询创建一个DTO。当然,您可以使用非类型化记录,如下所示:
Result<Record> result =
ctx.select(T.A, T.B)
.from(T)
.fetch();
然后
for (Record record : result)
System.out.println(record.get(T.A) + ":" + record.get(T.B));
在这里,我将通过创建N个方法来创建混乱因为我必须弄清楚4个列我必须使用方法X而对于5个列我必须使用方法Y,这将更加糟糕当你拥有100个开发人员的团队因为每个人都可能没有努力找到正确的方法,而是他/她在那里创建自己,这将创建冗余和重复的代码。
仅仅因为许多jOOQ示例使用准静态SQL语法来简化并不意味着您无法编写动态SQL。实际上,每个jOOQ语句都是动态SQL语句。例如:
List<Field<?>> select = new ArrayList<>();
if (something)
select.add(T.A);
if (somethingElse)
select.add(T.B);
Result<?> result = ctx.select(select).from(T).fetch();
进一步阅读:https://blog.jooq.org/2017/01/16/a-functional-programming-approach-to-dynamic-sql-with-jooq
因此,对于任何选择,我只需要编写一个方法,例如。我们称之为工厂类中的List findData(SearchCriteria sc)(M将其称为工厂,因为它将具有来自DAO的方法和对象,并且使用DAO将提供Bean的List,因此它将成为使用ORM的数据库中的对象生成器类) 。
您是否正在寻找Spring Data?
希望你明白我的意思。
不是真的,但我希望你能得到我的:)
所以,你增加了很多额外的问题。以下是我的答案:
在这里,ACTOR看起来像实际的表名和FIRST_NAME,因为它有任何标准,我们必须遵循某些代码实践,或者我必须自己设计它
jOOQ可让您使用开箱即用的功能,或者您可以花几天时间自定义jOOQ。如果你在这里不知道答案,只需使用jOOQ的默认值。他们很好的选择。
//我不知道怎么做*但会分别弄明白
您可以将select()
列表留空,或者调用selectFrom()
,或使用DSL.asterisk()
那么JOOQ是否列出了任何练习或模式建议?
同样,jOOQ并不会因为你自己的风格而判断你,它可以让你用它做你想做的事,而不会妨碍你。但是jOOQ有“明显的”默认值
现在在这种情况下,理想情况下,而不是创建一个单独的整个新Bean我的想法是,必须有UserBankAcctJoinBean应该能够处理此数据提取(这里必须考虑动态选择)
如果您认为这是一个非常好且可扩展的想法,那就去做吧。你可以自己编写bean。或者只使用jOOQ的记录,这些记录与元组不同。
如果JOOQ遵循JPA模式
我不知道这意味着什么或为什么你认为jOOQ这样做。
因为如果我想使用多种不同列的4-5种不同方式,那么我必须使用4-5种不同的重载构造函数,或者必须创建4-5种不同的Bean / POJO / DTO(这一点在我以前的编辑中已经存在)
如果您担心这一点,那么不要使用不可变的POJO,使用可变的POJO和JavaBeans样式的setter和getter,而jOOQ只会调用结果集中存在匹配列的那些。