2014-10-07 40 views
5

để mô hình cơ sở dữ liệu của tôi giống như thế này: Tôi có Store s và mỗi Store đều có tên được bản địa hóa. Vì vậy, tôi đã chọn để đại diện cho tên cục bộ như một Map như thế này:Cách truy vấn các giá trị Bản đồ với JPA dữ liệu Spring?

public class Store { 
    private Map<Locale,LocalizedValue> name; 
} 

như bạn có thể nhìn thấy nó là một bản đồ của <Locale, LocalizedValue> nơi LocalizedValue là một lớp học như thế này:

@Embeddable 
public class LocalizedValue { 

    @Column(name = "value") 
    private String value; 
} 

và nó tất cả hoạt động tốt. Tuy nhiên tôi nhận được một vấn đề mà tôi muốn truy vấn kho dữ liệu Spring JPA của tôi và tìm tất cả các cửa hàng với một tên tiếng Anh cụ thể. Vì vậy, phương pháp kho của tôi trông như thế này:

Store findByName(Map.Entry<Locale, LocalizedValue> name); 

nhưng nó ném ngoại lệ này:

2014-10-07 23:49:55,862 [qtp354231028-165] ERROR: Parameter value [en=Some Value] did not match expected type [com.test.LocalizedValue(n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [en=Some Value] did not match expected type [com.test.LocalizedValue (n/a)] 
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [en=Some Value] did not match expected type [com.test.LocalizedValue (n/a)]; 
nested exception is java.lang.IllegalArgumentException: Parameter value [en=Some Value] did not match expected type [com.test.LocalizedValue (n/a)] 
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:384) 
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:216) 
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417) 
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) 
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) 

Vì vậy, sau đó tôi đã thay đổi phương pháp kho của tôi là như thế này:

Store findByName(LocalizedValue name); 

nhưng sau đó tôi có ngoại lệ này:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'name1_.pk' in 'where clause' 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526) 

Tôi cũng đã thử sử dụng Chứa trong phương thức truy vấn - vẫn không có may mắn.

Vì vậy, câu hỏi của tôi là: Có cách nào để truy vấn các cửa hàng có tên tiếng Anh là 'Một số giá trị' không?

Trả lời

7

Điều này đòi hỏi một cái gì đó truy vấn bằng tay được định nghĩa như thế này:

interface StoreRepository extends Repository<Store, Long> { 

    @Query("select s from Store s join s.map m where ?1 in (VALUE(m))" 
    Optional<Store> findByName(String name); 
} 

Về cơ bản nó nói với các nhà cung cấp kiên trì để mở rộng các giá trị bản đồ và kiểm tra xem các thông số đưa ra là trong danh sách các giá trị mở rộng.

+2

Cảm ơn câu trả lời của bạn. Tài liệu này có được ghi trong Spring JPA không? Tôi có thể tìm thêm thông tin về cách các giá trị bản đồ được mở rộng bởi Spring JPA. – Sharadr

+0

Có thể thực hiện tương tự với thông số Bộ sưu tập không? – mihn

1

Bạn chưa đăng bản đồ nhưng có vẻ như tôi là một vấn đề cơ bản với cách mà các Embeddables được khóa.

Đây là cách rõ ràng duy nhất tôi có thể thấy để lập bản đồ liên kết:

@Entity 
@Table(name = "stores") 
public class Store { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "id") 
    private Long id; 

    @ElementCollection 
    @CollectionTable(name = "store_names", joinColumns = @JoinColumn(name = "store_id")) 
    @MapKeyColumn(name = "locale") 
    private Map<Locale, LocalizedName> names; 

    public Map<Locale, LocalizedName> getNames() { 
     return names; 
    } 

    public String getName(Locale locale) { 
     return names.get(locale).getName(); 
    } 
} 


@Embeddable 
public class LocalizedName { 

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

    @SuppressWarnings("unused") 
    private LocalizedName() { 

    } 

    public LocalizedName(String name) { 
     this.name = name; 
    } 

    public String getName(){ 
     return name; 
    } 
} 

Các thử nghiệm sau đi: Tuy nhiên

@Test 
public void testLoadStore() { 
    Store store = repository.findOne(1l); 
    Assert.assertNotNull(store); 
    Assert.assertEquals("EN Name", store.getName(Locale.ENGLISH)); 
    Assert.assertEquals("DE Name", store.getName(Locale.GERMAN)); 
} 

Vấn đề với điều này là 'Locale' không bao giờ có thể một thuộc tính của LocalisedName nếu không Hibernate than phiền về ánh xạ cột trùng lặp. Xem các báo cáo lỗi:

https://hibernate.atlassian.net/browse/HHH-5393

Vì vậy, trong khi chúng ta có thể viết một phương pháp truy vấn:

public interface StoreRepository kéo dài JpaRepository {

@Query(value = "from Store s join s.names n where n.name = ?1") 
Store findByName(String name); 

}

mà bài kiểm tra sau đây vượt qua

@Test 
public void testLoadByName() { 
    Store store = repository.findByName("EN Name"); 
    Assert.assertNotNull(store); 
    Assert.assertEquals("EN Name", store.getName(Locale.ENGLISH)); 
    Assert.assertEquals("DE Name", store.getName(Locale.GERMAN)); 
} 

như xa như tôi có thể thấy điều này không bao giờ có thể đưa Locale vào tài khoản vì nó không phải là tài sản của LocalizedName.

+0

Không, tất nhiên nó sẽ không hoạt động - bạn không bao giờ chỉ định miền địa phương. Tôi đã thử nó và tôi nhận được: "Giá trị tham số [Một số giá trị] không khớp với loại dự kiến ​​[com.test.LocalizedValue (n/a)];" –

+0

Xem câu trả lời cập nhật. –

Các vấn đề liên quan