2014-02-25 41 views
1

我在使用簡單的Spring數據查詢或@Query或QueryDSL在Spring Data中構建查詢時遇到了問題。如何在Spring數據中選擇不同的結果

如何選擇對於三列(Study,Country,Login)將是不同的行,並且作爲查詢的結果將是User的對象類型列表?

表:

------------------------------------- | User | ------------------------------------- | Id | Study | Country | Site | Login | ------------------------------------- | 1 | S1 | US | 11 | user1 | | 2 | S1 | US | 22 | user1 | | 3 | S1 | US | 33 | user1 | | .. | .. | .. | .. | .. | -------------------------------------

我需要它僅僅基於Study將返回唯一用戶爲每個查詢和Country而且沒有考慮到Site列。

方法簽名是象下面這樣:

List<User> findByStudyIgnoreCase(String study); 

而現在正在返回從表的用戶所有行。所以我在研究和國家中重複了有關用戶分配的行,因爲我在其他表中不需要Site的其他表中的UI演示文稿。

所以,我需要這樣的:

select distinct Study, Country, Login from User 

但返回的對象必須是用戶對象就像方法簽名稱(例如第一個匹配的結果)。

怎麼辦?

  1. 以這種方式或類似的方式可能嗎?如何使其正確?

    @Query("SELECT DISTINCT s.study, s.country, s.login FROM user s where s.study = ?1 ") List<User> findByStudyIgnoreCase(String study);

  2. 使用QueryDSL這可能嗎?

---- ----編輯

我試圖通過QueryDSL編寫查詢像TimoWestkämper建議,但我有一個問題。

public List<User> findByStudyIgnoreCase(String study) { 
     QUser $ = QUser.user; 
     BooleanExpression studyExists = $.study.equalsIgnoreCase(study); 

     List<Users> usersList = from($) 
      .where(studyExists) 
      .distinct() 
      .list(Projections.bean(User.class, $.study, $.country, $.id.login)); 

     return usersList; 
    } 

上面的查詢電話後出現異常:

org.springframework.dao.InvalidDataAccessApiUsageException: The bean of type: com.domain.app.model.User has no property called: study; nested exception is java.lang.IllegalArgumentException: The bean of type: com.domain.app.model.User has no property called: study 

爲什麼會發生?

---- EDIT 2 ----

User類:

@Entity 
@Table(name="USER") 
@Immutable 
@Builder 
@NoArgsConstructor 
@AllArgsConstructor 
@Getter @EqualsAndHashCode @ToString 
@FieldDefaults(level=AccessLevel.PRIVATE) 
public class User { 

    @EmbeddedId 
    UserId id; 

    @Column(name="CONTACT_UNIQUE_ID") 
    String contactUniqueId; 

    String country; 

    @Column(name="COUNTRY_CODE") 
    String countryCode; 

    @Column(name="STUDY") 
    String study; 

    String firstname; 

    String lastname; 

    String email; 

    String role; 
} 

嵌入式UserId類:

@Embeddable 
@Getter @EqualsAndHashCode @ToString 
@NoArgsConstructor 
@AllArgsConstructor 
@FieldDefaults(level=AccessLevel.PRIVATE) 
public class UserId implements Serializable { 

    private static final long serialVersionUID = 1L; 

    String site; 
    String login; 

} 

生成QUSER類:

@Generated("com.mysema.query.codegen.EntitySerializer") 
public class QUser extends EntityPathBase<User> { 

    private static final long serialVersionUID = 1646288729; 

    private static final PathInits INITS = PathInits.DIRECT; 

    public static final QUser user = new User("user"); 

    public final StringPath contactUniqueId = createString("contactUniqueId"); 

    public final StringPath country = createString("country"); 

    public final StringPath countryCode = createString("countryCode"); 

    public final StringPath study = createString("study"); 

    public final StringPath email = createString("email"); 

    public final StringPath firstname = createString("firstname"); 

    public final QUser id; 

    public final StringPath lastname = createString("lastname"); 

    public final StringPath role = createString("role"); 

    public QUser(String variable) { 
     this(User.class, forVariable(variable), INITS); 
    } 

    @SuppressWarnings("all") 
    public QUser(Path<? extends User> path) { 
     this((Class)path.getType(), path.getMetadata(), path.getMetadata().isRoot() ? INITS : PathInits.DEFAULT); 
    } 

    public QUser(PathMetadata<?> metadata) { 
     this(metadata, metadata.isRoot() ? INITS : PathInits.DEFAULT); 
    } 

    public QUser(PathMetadata<?> metadata, PathInits inits) { 
     this(User.class, metadata, inits); 
    } 

    public QUser(Class<? extends User> type, PathMetadata<?> metadata, PathInits inits) { 
     super(type, metadata, inits); 
     this.id = inits.isInitialized("id") ? new QUser(forProperty("id")) : null; 
    } 

} 
+0

這是可能的嗎?你爲什麼不嘗試它? –

+0

@JBNizet我試過了,而不是用戶我只有學習,國家和登錄值的對象,所以它不是我所期待的... – Roman

+0

這是相當期望的,因爲您的查詢選擇研究,國家和登錄。 –

回答

1

我可以回答Querydsl部分。它通過

List<User> users = query.from(user) 
    .where(user.study.eq(arg)) 
    .distinct() 
    .list(Projections.fields(User.class, user.study, user.country, user.login)); 

您將得到具有填充的研究,國家和登錄字段的用戶實例。用戶實例不是託管的JPA實體,而是填充的bean。

另外,您可以查詢元組的情況下,這樣的

List<Tuple> tuples = query.from(user) 
    .where(user.study.eq(arg)) 
    .distinct() 
    .list(user.study, user.country, user.login); 

但是當你使用Spring的數據你可能要返回用戶來代替。

+0

感謝您的回答,我嘗試了您的第一個建議,但我得到org.springframework.dao.InvalidDataAccessApiUsageException:類型爲com.domain.app.model.User的bean沒有名爲study的屬性;與其他2個屬性相同。我已經生成謂詞(其他查詢有效),但爲什麼財產在這裏不可見?請在更新後的答案內容中查看我的dslquery。 – Roman

+0

用戶是否有學習,國家和登錄bean屬性? –

+0

是的。我告訴你我是如何以其他(不優雅)方式解決問題的:1查詢所有行,然後用其他方法縮小結果。但我相信應該可以只寫一個適當的查詢。你可以看看嗎? – Roman

0

我解決了所有行調用一般查詢的問題,然後縮小了其他方法的結果。對我來說這不是更好的解決方案,但我想告訴你我的需要。也許你會找到更好的解決方案,只有查詢。是否有可能只包含在一個查詢中?

public List<User> findDistinctUsersByStudyNumIgnoreCase(String study) { 
    QUser $ = QUser.user; 
    BooleanExpression studyExists = $.study.equalsIgnoreCase(study); 

    List<User> usersList = from($) 
     .where(study) 
     .listDistinct($); 

    // narrowing results (this what I do not know how to use in QueryDsl query) 
    usersList = removeDuplicates(usersList); 

    return usersList; 
} 

/** 
* <p>Remove duplicated user assignments for presentation User table purpose only</p> 
* <p><b>NOTE:</b> Duplicated assignment is when more than one entry in USER 
* has the same <i>study</i>, <i>country</i>, <i>login</i> and differ with <i>site</i> only. 
* For presentation User Assignments table purpose the <i>site</i> context is not needed, so we need 
* only info about user existence in <i>study</i> and <i>country</i> context only.</p> 
* @param usersList user assignments list from USER with study, country and site context (with duplicates) 
* @return distinct user assignments list narrowed to study and country context only and without site context (without duplicates) 
*/ 
private List<User> removeDuplicates(List<User> usersList) { 
    List<User> result = new ArrayList<User>(); 

    MultiKeyMap studyCountryLoginMap = new MultiKeyMap(); 
    for (User u : usersList) { 
     if (!studyCountryLoginMap.containsKey(u.getStudy(), u.getCountry(), u.getId().getLogin())) { 
      studyCountryLoginMap.put(u.getStudy(), u.getCountry(), u.getId().getLogin(), u); 
     } 
    } 

    result.addAll(studyCountryLoginMap.values()); 
    return result; 
} 
相關問題