List 유형의 필드를 가진 엔티티를 유지하는 가장 똑똑한 방법은 무엇입니까?
Command.java
package persistlistofstring;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;
@Entity
public class Command implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Basic
List<String> arguments = new ArrayList<String>();
public static void main(String[] args) {
Command command = new Command();
EntityManager em = Persistence
.createEntityManagerFactory("pu")
.createEntityManager();
em.getTransaction().begin();
em.persist(command);
em.getTransaction().commit();
em.close();
System.out.println("Persisted with id=" + command.id);
}
}
이 코드는 다음을 생성합니다.
> Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named pu: Provider named oracle.toplink.essentials.PersistenceProvider threw unexpected exception at create EntityManagerFactory:
> oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Local Exception Stack:
> Exception [TOPLINK-30005] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: sun.misc.Launcher$AppClassLoader@11b86e7
> Internal Exception: javax.persistence.PersistenceException: Exception [TOPLINK-28018] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.EntityManagerSetupException
> Exception Description: predeploy for PersistenceUnit [pu] failed.
> Internal Exception: Exception [TOPLINK-7155] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.ValidationException
> Exception Description: The type [interface java.util.List] for the attribute [arguments] on the entity class [class persistlistofstring.Command] is not a valid type for a serialized mapping. The attribute type must implement the Serializable interface.
> at oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:143)
> at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.createEntityManagerFactory(EntityManagerFactoryProvider.java:169)
> at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:110)
> at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83)
> at persistlistofstring.Command.main(Command.java:30)
> Caused by:
> ...
답변
JPA 2 구현을 사용하십시오 : Hibernate와 비슷한 @ElementCollection 주석을 추가하여 필요한 것을 정확하게 수행합니다. 여기에 한 가지 예가 있습니다 .
편집하다
아래 의견에서 언급했듯이 올바른 JPA 2 구현은
javax.persistence.ElementCollection
@ElementCollection
Map<Key, Value> collection;
참조 : http://docs.oracle.com/javaee/6/api/javax/persistence/ElementCollection.html
답변
오래된 스레드를 되살려 미안하지만 누구나 문자열 목록을 데이터베이스에 하나의 필드로 저장하는 대체 솔루션을 찾고 있어야합니다. 여기에서 해결했습니다. 다음과 같이 변환기를 작성하십시오.
import java.util.Arrays;
import java.util.List;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class StringListConverter implements AttributeConverter<List<String>, String> {
private static final String SPLIT_CHAR = ";";
@Override
public String convertToDatabaseColumn(List<String> stringList) {
return String.join(SPLIT_CHAR, stringList);
}
@Override
public List<String> convertToEntityAttribute(String string) {
return Arrays.asList(string.split(SPLIT_CHAR));
}
}
이제 다음과 같이 엔터티에서 사용하십시오.
@Convert(converter = StringListConverter.class)
private List<String> yourList;
데이터베이스에서 목록은 foo; bar; foobar로 저장되며 Java 객체에는 해당 문자열이 포함 된 목록이 표시됩니다.
이것이 누군가에게 도움이되기를 바랍니다.
답변
이 답변은 JPA2 이전에 구현되었으며 JPA2를 사용하는 경우 위의 ElementCollection 답변을 참조하십시오.
모델 개체 내부의 개체 목록은 일반적으로 다른 개체와의 “OneToMany”관계로 간주됩니다. 그러나 문자열 자체는 ID가 없기 때문에 일대 다 관계의 허용 가능한 클라이언트가 아닙니다.
그래서, 당신은 해야 인수 급 JPA의 목록에 문자열 목록을 변환 ID와 문자열을 포함하는 객체. 문자열을 ID로 사용하면 잠재적으로 ID 필드를 제거하고 문자열이 동일한 행을 통합하여 테이블의 공간을 절약 할 수 있지만 인수를 원래 순서로 다시 정렬하는 기능을 잃을 수 있습니다 (주문 정보를 저장하지 않았으므로).
또는 목록을 @Transient로 변환하고 클래스에 VARCHAR () 또는 CLOB 인 다른 필드 (argStorage)를 추가 할 수 있습니다. 그런 다음 3 개의 함수를 추가해야합니다. 그 중 2 개는 동일하며 문자열 목록을 쉽게 분리 할 수있는 방식으로 구분 된 단일 문자열 (argStorage)로 변환해야합니다. @PrePersist 및 @PreUpdate를 사용하여이 두 가지 기능 (각각 동일한 기능)에 주석을 답니다. 마지막으로 argStorage를 문자열 목록으로 다시 분할하는 세 번째 함수를 추가하고 @PostLoad에 주석을 답니다. 이렇게하면 명령을 저장할 때마다 CLOB가 문자열로 업데이트되고 argStorage 필드가 DB에 저장되기 전에 업데이트됩니다.
나는 여전히 첫 번째 사례를 제안합니다. 나중에 실제 관계를 유지하는 것이 좋습니다.
답변
Hibernate 를 사용한 Java Persistence 에 따르면
주석으로 값 유형의 콜렉션 맵핑 […]. 작성 당시에는 Java Persistence 표준의 일부가 아닙니다.
최대 절전 모드를 사용하는 경우 다음과 같은 작업을 수행 할 수 있습니다.
@org.hibernate.annotations.CollectionOfElements(
targetElement = java.lang.String.class
)
@JoinTable(
name = "foo",
joinColumns = @JoinColumn(name = "foo_id")
)
@org.hibernate.annotations.IndexColumn(
name = "POSITION", base = 1
)
@Column(name = "baz", nullable = false)
private List<String> arguments = new ArrayList<String>();
업데이트 : 이제 JPA2에서 사용할 수 있습니다.
답변
이것을 사용할 수도 있습니다.
@Column(name="arguments")
@ElementCollection(targetClass=String.class)
private List<String> arguments;
답변
나는 같은 문제가 있었기 때문에 주어진 가능한 해결책에 투자했지만 결국에는 ‘;’ 분리 된 문자열 목록.
그래서 나는 가지고있다
// a ; separated list of arguments
String arguments;
public List<String> getArguments() {
return Arrays.asList(arguments.split(";"));
}
이런 식으로 데이터베이스 테이블에서 목록을 쉽게 읽고 편집 할 수 있습니다.
답변
JPA의 Hibernate 구현을 사용할 때, 단순히 List 대신 ArrayList로 유형을 선언하면 최대 절전 모드가 데이터 목록을 저장할 수 있다는 것을 알았습니다.
분명히 이것은 Entity 객체 목록을 만드는 것과 비교하여 많은 단점이 있습니다. 게으른 로딩이나 다른 개체에서 목록의 엔터티를 참조 할 수 없으며 데이터베이스 쿼리를 구성하는 데 어려움이있을 수 있습니다. 그러나 엔터티와 함께 항상 열심히 가져오고 싶은 상당히 원시적 인 유형의 목록을 처리 할 때이 접근법은 나에게 잘 보입니다.
@Entity
public class Command implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
ArrayList<String> arguments = new ArrayList<String>();
}