如何使用 Hibernate 构建 DSL 路径
How to build DSL paths with Hibernate
有没有办法用 Hibernate 实现 DSL 查询?我的意思主要是更容易和打字更安全的 HQL 语句构建。例如,像这样的 HQL 查询:select u.id from Users u where u.person.identityCard.lastName like :lastNameVar
可以这样写:
Select.from(User.class, “u”).where(eq(“u”, User.person().identityCard().lastName(), lastNameVar))
作为实验,我已经编写了构建器本身,但我似乎无法弄清楚如何制作那些多步 DSL 路径 (User.person().identityCard().lastName()
)。我显然必须向我的实体 类 添加一些东西,例如:
@Entity
public class User {
public static DSLProperty<Person> person() = new DSLProperty<>(“person”); // how do I write DSLProperty class to achieve this?
@OneToOne
@JoinColumn(name=“person_id”)
private Person person;
//getters, setters etc.
}
但是我似乎缺乏关于如何调用抽象的命名方法的知识 类 就像 DSLProperty
在链接 属性 路径时。
P.s。这更多是我想自己弄清楚的实验性功能。我知道 QueryDSL 和 jOOQ 等库,但我不确定它们是否支持 属性 链接,而且,我更感兴趣的是从头开始实现此功能。
旧的和冗长的解决方案 -- CriteriaBuilder
调制解调器一 -- QueryDSL
所以,花了一些时间解决这个问题(正如我所说,这更像是一个实验性的东西)我得出了这样的解决方案:
首先,我创建了一个基地DSLProperty.class
:
public class DSLProperty {
protected String previousPath; // this will hold the path till the current step of the path chain
public DSLProperty( String previousPath ) {
this.previousPath = previousPath;
}
public String getPath() { return previousPath; }
}
然后,在我的抽象基础实体中 class 我创建了这样的静态内部 class:
public static class DSL extends DSLProperty {
protected DSL( String input ) {
super( input );
}
public DSLProperty id() {
return property( "id" );
}
protected DSLProperty property( String property ) {
return new DSLProperty( ( previousPath != null ? previousPath + "." : "" ) + property );
}
}
并且基本上在所有子实体中扩展(可能使用您的 IDE 或 Maven 生成)这个基础 DSL
class,例如DSLTestUser.class
:
@Entity
@Table
public class DSLTestUser extends DSLTestBaseEntity {
public static DSL alias( String alias ) { return new DSL( alias ); }
public static class DSL extends DSLTestBaseEntity.DSL {
public DSL( String input ) {
super( input );
}
public DSLProperty username() { return property( "username" ); }
public DSLTestPerson.DSL person() { return DSLTestPerson.alias( previousPath + ".person" ); }
}
// all the columns, getters & setters etc.
}
和DSLTestPerson.class
:
@Entity
@Table
public class DSLTestPerson extends DSLTestBaseEntity {
public static DSL alias( String alias ) { return new DSL( alias ); }
public static class DSL extends DSLTestBaseEntity.DSL {
public DSL( String input ) {
super( input );
}
public DSLProperty name() { return property( "name" ); }
public DSLTestUser.DSL user() { return DSLTestUser.alias( previousPath + ".user" ); }
}
// all the columns, getters & setters etc.
}
这样,这段代码:
System.out.println( DSLTestUser.alias( "tu" ).person().id().getPath() );
System.out.println( DSLTestUser.alias( "tu" ).username().getPath() );
System.out.println( DSLTestPerson.alias( "tp" ).user().username().getPath() );
System.out.println( DSLTestPerson.alias( "tp" ).getPath() );
将产生以下输出:
tu.person.id
tu.username
tp.user.username
tp
路径链的长度没有限制,您可以使用此特定于域的 属性 路径生成以任何方式生成 HQL 查询。
唯一让我有点烦恼的是您需要编写的代码量(同样,您可以生成它)以及将为每个路径创建多少对象(取决于步骤量),但此解决方案的 pro 是,如果您更改 属性 的名称,您将不必担心找到它在 HQL 查询中使用的所有位置- 只需使用 IDE 的重构功能更改相应内部 DSL
class 中的 属性。
有没有办法用 Hibernate 实现 DSL 查询?我的意思主要是更容易和打字更安全的 HQL 语句构建。例如,像这样的 HQL 查询:select u.id from Users u where u.person.identityCard.lastName like :lastNameVar
可以这样写:
Select.from(User.class, “u”).where(eq(“u”, User.person().identityCard().lastName(), lastNameVar))
作为实验,我已经编写了构建器本身,但我似乎无法弄清楚如何制作那些多步 DSL 路径 (User.person().identityCard().lastName()
)。我显然必须向我的实体 类 添加一些东西,例如:
@Entity
public class User {
public static DSLProperty<Person> person() = new DSLProperty<>(“person”); // how do I write DSLProperty class to achieve this?
@OneToOne
@JoinColumn(name=“person_id”)
private Person person;
//getters, setters etc.
}
但是我似乎缺乏关于如何调用抽象的命名方法的知识 类 就像 DSLProperty
在链接 属性 路径时。
P.s。这更多是我想自己弄清楚的实验性功能。我知道 QueryDSL 和 jOOQ 等库,但我不确定它们是否支持 属性 链接,而且,我更感兴趣的是从头开始实现此功能。
旧的和冗长的解决方案 -- CriteriaBuilder
调制解调器一 -- QueryDSL
所以,花了一些时间解决这个问题(正如我所说,这更像是一个实验性的东西)我得出了这样的解决方案:
首先,我创建了一个基地DSLProperty.class
:
public class DSLProperty {
protected String previousPath; // this will hold the path till the current step of the path chain
public DSLProperty( String previousPath ) {
this.previousPath = previousPath;
}
public String getPath() { return previousPath; }
}
然后,在我的抽象基础实体中 class 我创建了这样的静态内部 class:
public static class DSL extends DSLProperty {
protected DSL( String input ) {
super( input );
}
public DSLProperty id() {
return property( "id" );
}
protected DSLProperty property( String property ) {
return new DSLProperty( ( previousPath != null ? previousPath + "." : "" ) + property );
}
}
并且基本上在所有子实体中扩展(可能使用您的 IDE 或 Maven 生成)这个基础 DSL
class,例如DSLTestUser.class
:
@Entity
@Table
public class DSLTestUser extends DSLTestBaseEntity {
public static DSL alias( String alias ) { return new DSL( alias ); }
public static class DSL extends DSLTestBaseEntity.DSL {
public DSL( String input ) {
super( input );
}
public DSLProperty username() { return property( "username" ); }
public DSLTestPerson.DSL person() { return DSLTestPerson.alias( previousPath + ".person" ); }
}
// all the columns, getters & setters etc.
}
和DSLTestPerson.class
:
@Entity
@Table
public class DSLTestPerson extends DSLTestBaseEntity {
public static DSL alias( String alias ) { return new DSL( alias ); }
public static class DSL extends DSLTestBaseEntity.DSL {
public DSL( String input ) {
super( input );
}
public DSLProperty name() { return property( "name" ); }
public DSLTestUser.DSL user() { return DSLTestUser.alias( previousPath + ".user" ); }
}
// all the columns, getters & setters etc.
}
这样,这段代码:
System.out.println( DSLTestUser.alias( "tu" ).person().id().getPath() );
System.out.println( DSLTestUser.alias( "tu" ).username().getPath() );
System.out.println( DSLTestPerson.alias( "tp" ).user().username().getPath() );
System.out.println( DSLTestPerson.alias( "tp" ).getPath() );
将产生以下输出:
tu.person.id
tu.username
tp.user.username
tp
路径链的长度没有限制,您可以使用此特定于域的 属性 路径生成以任何方式生成 HQL 查询。
唯一让我有点烦恼的是您需要编写的代码量(同样,您可以生成它)以及将为每个路径创建多少对象(取决于步骤量),但此解决方案的 pro 是,如果您更改 属性 的名称,您将不必担心找到它在 HQL 查询中使用的所有位置- 只需使用 IDE 的重构功能更改相应内部 DSL
class 中的 属性。