问题
I'm using Spring JPA and I need to have a native query. With that query, I need to get only two fields from the table, so I'm trying to use Projections. It isn't working, this is the error I'm getting:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.example.IdsOnly]
I tried to follow precisely the instructions of that page I linked, I tried to make my query non-native (do I actually need it to be native if I use projections, btw?), but I always get that error.
If I use an interface it works, but the results are proxies and I really need them to be "normal results" that I can turn into json.
So, here's my code. The Entity:
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Entity
@Table(name = "TestTable")
public class TestTable {
@Id
@Basic(optional = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "Id")
private Integer id;
@Column(name = "OtherId")
private String otherId;
@Column(name = "CreationDate")
@Temporal(TemporalType.TIMESTAMP)
private Date creationDate;
@Column(name = "Type")
private Integer type;
}
The class for the projection:
import lombok.Value;
@Value // This annotation fills in the "hashCode" and "equals" methods, plus the all-arguments constructor
public class IdsOnly {
private final Integer id;
private final String otherId;
}
The Repository:
public interface TestTableRepository extends JpaRepository<TestTable, Integer> {
@Query(value = "select Id, OtherId from TestTable where CreationDate > ?1 and Type in (?2)", nativeQuery = true)
public Collection<IdsOnly> findEntriesAfterDate(Date creationDate, List<Integer> types);
}
And the code that tries to get the data:
@Autowired
TestTableRepository ttRepo;
...
Date theDate = ...
List<Integer> theListOfTypes = ...
...
Collection<IdsOnly> results = ttRepo.findEntriesAfterDate(theDate, theListOfTypes);
Thanks for the help. I really don't understand what I'm doing wrong.
回答1:
The query should be using a constructor expression:
@Query("select new com.example.IdsOnly(t.id, t.otherId) from TestTable t where t.creationDate > ?1 and t.type in (?2)")
And i dont know Lombok, but make sure there is a constructor that takes the two IDs as parameters.
回答2:
with spring data you can cut the middle-man and simply define
public interface IdsOnly {
Integer getId();
String getOtherId();
}
and use a native query like;
@Query(value = "Id, OtherId from TestTable where CreationDate > ?1 and Type in (?2)", nativeQuery = true)
public Collection<IdsOnly> findEntriesAfterDate(Date creationDate, List<Integer> types);
check out https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
回答3:
JPA 2.1 introduces an interesting ConstructorResult feature if you want to keep it native.
回答4:
You can return list of Object Array (List) as return type of the native query method in repository class.
@Query(
value = "SELECT [type],sum([cost]),[currency] FROM [CostDetails] " +
"where product_id = ? group by [type],[currency] ",
nativeQuery = true
)
public List<Object[]> getCostDetailsByProduct(Long productId);
for(Object[] obj : objectList){
String type = (String) obj[0];
Double cost = (Double) obj[1];
String currency = (String) obj[2];
}
回答5:
I need to map values from 2 tables and solved like this in Repository file
@Query("select distinct emp.user.id as id, " +
"concat(emp.user.firstName, ' ',emp.user.lastName, ' ',emp.extensionNumber) as name from NmsEmployee emp " +
" where emp.domain.id = :domainId and (emp.activeUntil= null or emp.activeUntil > :lLogin) ")
List<Selectable> getSelcByDomainId( @Param("domainId") Long domainId, @Param("lLogin") ZonedDateTime lLogin);
Where Selectable is
public interface Selectable {
Long getId();
String getName();
}
来源:https://stackoverflow.com/questions/49500309/spring-jpa-native-query-with-projection-gives-converternotfoundexception