Spring规范与@query

huangapple go评论77阅读模式
英文:

Spring Specification with @query

问题

我有一个名为'content'的表,其中有一个名为'created_at'的字段。
我正在尝试在此表中使用可分页和规范。

规范部分运行正常,但是可分页部分出了问题。如果我使用存储库中继承的方法来搜索,可分页无法识别带有下划线的字段,并尝试对其进行拆分。导致出现以下错误:

“找不到类型为Content的属性created!”

如果我在存储库中创建一个方法,可分页可以工作,但规范则不行。
以下是我的存储库代码:

@Repository
public interface ContentRepository extends JpaRepository<Content, String>,
JpaSpecificationExecutor<Content> {

   @Query(value = "SELECT * FROM content", nativeQuery = true)
   public Page<Content> findAll(Specification<Content> specification, Pageable pageable);    

}

如何同时实现这两个功能?

Content类:

 @Entity
 @Table(name = "content")
 @Setter
 @Getter
 public class Content {

  @Id
  @Column(name = "id")
  private String id;

  @Column
  private String name;

  @Column
  private String description;

  @Column(columnDefinition = "TEXT")
  private String content;

  @Column(columnDefinition = "TEXT")
  private String reference;

  @ManyToOne
  @JoinColumn(nullable = false)
  private User author;

  @ManyToOne
  @JoinColumn(nullable = true)
  private Agenda agenda;

  @ManyToOne
  @JoinColumn(nullable = false)
  private ContentType contenttype;

  @Column(columnDefinition = "boolean default true")
  private boolean enabled;

  @Column(columnDefinition = "boolean default false")
  private boolean approved;

  @Column
  private Date sent_at;
  @Column
  private Date created_at;
  @Column
  private Date updated_at;
  @Column
  private Date deleted_at;

}
英文:

I have a table named 'content' which has a field named 'created_at'.
I am trying to use pageable and specifications in this table.

Specifications works perfectly but i have a problem with pageable. If i use the inherited method from the repository to search the pageable don't recognize the field with underscore and tries to split him. Givin this error:

&quot;No property created found for type Content!&quot;

If i create a method in the repository pageable works but specifications don't.
Here is my repository:

@Repository
public interface ContentRepository extends JpaRepository&lt;Content, 
String&gt;,JpaSpecificationExecutor&lt;Content&gt; {

   @Query(value = &quot;SELECT * FROM content&quot;, nativeQuery = true)
   public Page&lt;Content&gt; findAll(Specification&lt;Content&gt; specification, Pageable pageable);    

}

How can i do both?

Content class:

 @Entity
 @Table(name = &quot;content&quot;)
 @Setter
 @Getter
 public class Content {

  @Id
  @Column(name = &quot;id&quot;)
  private String id;

  @Column
  private String name;

  @Column
  private String description;

  @Column(columnDefinition = &quot;TEXT&quot;)
  private String content;

  @Column(columnDefinition = &quot;TEXT&quot;)
  private String reference;

  @ManyToOne
  @JoinColumn(nullable = false)
  private User author;

  @ManyToOne
  @JoinColumn(nullable = true)
  private Agenda agenda;

  @ManyToOne
  @JoinColumn(nullable = false)
  private ContentType contenttype;

  @Column(columnDefinition = &quot;boolean default true&quot;)
  private boolean enabled;

  @Column(columnDefinition = &quot;boolean default false&quot;)
  private boolean approved;

  @Column
  private Date sent_at;
  @Column
  private Date created_at;
  @Column
  private Date updated_at;
  @Column
  private Date deleted_at;

}

答案1

得分: 2

避免在实体属性名称中使用下划线,如果您能够控制属性命名的话。这将解决您的存储库问题,并使代码库更加清晰。在您之后处理代码的开发人员会感激您。

需要注意的是,这不仅仅是我的意见:Spring专门不建议使用下划线

> 由于我们将下划线视为保留字符,我们强烈建议遵循标准的Java命名约定(即在属性名称中不使用下划线,而是使用驼峰命名法)。

这个JIRA问题说明了为什么文档会更新为这个建议,并且删除了描述双下划线选项的部分。

我怀疑您的根本问题是Spring/Hibernate无法将驼峰命名的属性名称映射到数据库中列的下划线命名。您真正需要的是使您的属性名称在Hibernate生成的SQL中被解释为"created_at"。

这就是您的属性名称中的下划线是否是“必需”的原因吗?如果是的话,有几种解决方案:

选项1:@Column注解

为了让JPA/Hibernate映射到正确的列名,您可以明确告诉它要使用的列名。使用注解**@Column(name="...")**告诉它在SQL中使用什么列名。然后字段名称不受列名约束。

@Entity
@Table(name = "content")
@Setter
@Getter
public class Content {
     @Id
     @Column(name="created_at")
     private String createdAt;
}

选项2:改进的命名策略

如果您的应用程序有大量的实体,而不是为每个属性添加**@Column**,可以在配置文件中将默认的命名策略更改为hibernate improved naming strategy

<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>

这个命名策略将驼峰命名转换为SNAKE_CASE。然后您的类可能看起来就像这样:

@Entity
public class Content{
     @Id
     private String createdAt;
}

使用这两种选项中的任何一种,在创建SQL时都会将列名解析为:

created_at

注意:如果您正在使用Spring Boot,自动配置默认将使用SpringNamingStrategy,这是略微修改过的Hibernate改进策略。您不需要做任何操作即可获得这个改进的命名策略。

终点:

使用驼峰命名法在属性名称中,您可以使用驼峰命名法编写存储库方法名称,不再需要尝试处理双下划线:

@Repository
@Transactional
public interface ContentRepository extends CrudRepository<Content, String> {  
      @Query(value = "SELECT * FROM content", nativeQuery = true)
       List<Student> findAll(Specification<Content> specification, Pageable pageable);   
}
英文:

Avoid using underscores in the entity property names if you have control over the property naming. This will resolve your repository woes, and will result in a cleaner code-base. Developers dealing with the code after you will thank you.

Note, it's not just my opinion: Spring specifically discourages using underscores.

> As we treat underscore as a reserved character we strongly advise to
> follow standard Java naming conventions (i.e. not using underscores in
> property names but camel case instead).

this JIRA issue shows why the documentation was updated with this reccomendation, and the part describing the double underscore option were removed.

I suspect your root problem is that Spring/Hibernate is not mapping camel case property names to the snake case names you have for your columns in the database. What you really need is for your property name to be interpreted in the SQL that hiberate generates as created_at.

Is that why underscores in your property name are "required"? If so, there are a few solutions:

Option 1: @Column annotation

To get JPA/Hibernate to map to the correct column names you can tell it the names explicitly. Use the annotation @Column(name=&quot;...&quot;) to tell it what column names to use in SQL. Then the field names are not constrained by the column names.

<!-- language: java -->

@Entity
@Table(name = &quot;content&quot;)
@Setter
@Getter
public class Content {
     @Id
     @Column(name=&quot;created_at&quot;)
     private String createdAt;
}

Option 2: Improved Naming Strategy
Or if your application has a large number of entities, rather than adding @Column to every property, change the default naming strategy in your configuration file to the hibernate improved naming strategy.

<!-- language: xml -->

&lt;prop key=&quot;hibernate.ejb.naming_strategy&quot;&gt;org.hibernate.cfg.ImprovedNamingStrategy&lt;/prop&gt;

This naming strategy will convert camelCase to SNAKE_CASE. Then your class could look as simple as this:

<!-- language: java -->

@Entity
public class Content{
     @Id
     private String createdAt;

}

Using either of those options, when it creates the SQL it will resolve the column names to:

<!-- language: SQL -->

 created_at

Note: If you are using, or can use Spring Boot, the auto-configuration default will use SpringNamingStrategy, which is a slightly modified version of the hibernate improved strategy. You won't have to do anything to get this improved naming strategy.

The finish line:

Using camel case in your property names you can write your repository method name using camel case, and you can stop trying to wrangle the double underscore:

<!-- language: java -->

@Repository
@Transactional
public interface ContentRepository extends CrudRepository&lt;Content, String&gt; {  
      @Query(value = &quot;SELECT * FROM content&quot;, nativeQuery = true)
       List&lt;Student&gt; findAll(Specification&lt;Content&gt; specification, Pageable pageable);   
}

huangapple
  • 本文由 发表于 2020年8月26日 00:41:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/63583448.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定