将实体中的列表转换为数据库中的单个字符串列

Posted

技术标签:

【中文标题】将实体中的列表转换为数据库中的单个字符串列【英文标题】:Convert list in entity to single string column in database 【发布时间】:2016-03-07 01:29:56 【问题描述】:

我的数据库中有一个VARCHAR 字段,该字段的值为val1,val2,val3

是否可以使用逗号作为分隔符将其设置为实体的ArrayList<String> 属性?

【问题讨论】:

【参考方案1】:

如果您使用 JPA 2.1,那么您可以创建一个AttributeConverter

@Converter
public class StringListConverter implements AttributeConverter<List<String>, String> 

  @Override
  public String convertToDatabaseColumn(List<String> list) 
    // Java 8
    return String.join(",", list); 
    // Guava
    return Joiner.on(',').join(list); 
  

  @Override
  public List<String> convertToEntityAttribute(String joined) 
    return new ArrayList<>(Arrays.asList(joined.split(",")));
  


您可以在您的实体中使用此转换器:

@Column
@Convert(converter = StringListConverter.class)
private List<String> strings;

在 JPA 2.1 之前,您可以手动执行此操作:

@Entity
private MyEntity 
  ...
  private String strings;

  public List<String> getStrings() 
    return Arrays.asList(strings.split(","));
  

  public void setStrings(List<String> list) 
    strings = String.join(",", list);
  

我将Arrays.asList 包装在转换器的ArrayList 中,因为结果存储在属性中,对该列表的任何更改都将写回数据库 - 因此我需要一个可更改的列表(我不能将任何内容添加到Arrays.asList) 的结果中。在2.1之前的解决方案中,结果与属性无关,可更改的列表不会与属性同步。

要查询包含此类属性中特定项目的实体,请参阅我的答案here

【讨论】:

【参考方案2】:

是的,这是可能的。

使用 Hibernate 4.3.x+,您可以定义 AttributeConverter,尽管我很确定这不适用于早期的 Hibernate 版本,因为 List 类型。请参阅此示例:http://www.thoughts-on-java.org/jpa-21-how-to-implement-type-converter/

实现这项工作的另一种方法是实现自定义UserType 并使用org.hibernate.annotations.Type 注释字段/getter。这是一个很好的例子:http://blog.xebia.com/understanding-and-writing-hibernate-user-types/

另一种与 JPA 兼容的方法是使用两个字段,ListString听众自己。这里是一个使用监听器的例子:http://alexandregama.org/2014/03/23/entity-listeners-and-callback-methods-jpa/

【讨论】:

【参考方案3】:

尝试使用@ElementCollection 和@CollectionTable 注解

【讨论】:

你拯救了我的一天 不过,这不是问题所要求的。 确实如此。这将创建另一个表。不正确【参考方案4】:

如果您希望 String 中有逗号,split()/join() 将不够用。对于那些寻找更好/不同解决方案的人,这里是 - 通过序列化为 JSON 并从 JSON 反序列化。缺点是数据库中使用了更多字符,但它适用于您可以拥有的大部分文本。

package ...;

import java.io.Serializable;
import javax.persistence.AttributeConverter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class StringArrayConverter
        implements AttributeConverter<String[], String>, Serializable 

    private static final long serialVersionUID = -2744576922911393664L;

    @Override
    public String convertToDatabaseColumn(final String[] attribute) 
        try 
            return new ObjectMapper().writeValueAsString(attribute);
        
        catch (@SuppressWarnings("unused") final JsonProcessingException e) 
            // ignore
        
        return null;
    

    @Override
    public String[] convertToEntityAttribute(final String dbData) 
        try 
            return new ObjectMapper().readValue(dbData, String[].class);
        
        catch (@SuppressWarnings("unused") final JsonProcessingException e) 
            // ignore
        
        return null;
    


使用示例:

package ...;

import ....StringArrayConverter;

import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonView;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Getter @Setter @NoArgsConstructor
public class PersonWithCars 

    @Id @NotNull @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer id;
    
    private String name;

    @Convert(converter = StringArrayConverter.class)
    private String[] cars = new String[0];


【讨论】:

以上是关于将实体中的列表转换为数据库中的单个字符串列的主要内容,如果未能解决你的问题,请参考以下文章

使用 SQL 将字符串列转换为 mongodb 中的日期时间

将列表中的所有字符串转换为浮点数。适用于单个列表,但不适用于数据框

使用SQL将字符串列转换为mongodb中的日期时间

将日期时间列转换为字符串列

将带有日期和时间信息的字符串列转换为R [duplicate]中的datetime类型

将具有 AM/PM 的字符串列转换为 Impala 中的时间戳