I have Java code:
String updateSql = "UPDATE table_name SET field_two = :field_two"
+ " WHERE field_one = :field_one AND field_two <> :field_two";
handle.createUpdate(updateSql)
.bindBean(myBean)
.execute();
#Data
public class MyBean() {
private String fieldOne;
private String fieldTwo;
}
When Jdbi tries to bind the field_two the second time, it throws UnableToCreateStatementException: Missing named parameter field_two in binding.
How can I bind the field_two appeared multiple times in the query using bindBean()?
It turns out that the binding needs to have the same name with the field name:
String updateSql = "UPDATE table_name SET field_two = :fieldTwo"
+ " WHERE field_one = :fieldOne AND field_two <> :fieldTwo";
Related
I'm a newbie in Mybatis and I have a problem with getting data with #Many.
I have two classes, objects of the second class are values of first-class objects Set<>;
Classes are:
public class InformationObjectMergedWithCopyrights {
private Long id;
private String titleLt;
private String accountingNumber;
private String inventoryNumber;
private Long referenceYear;
private Long duration;
private String propertyRights;
private Set<BavicCredit> creditsList = new HashSet<>();
getters/setters, constructor, toString...
}
public class BavicCredit {
private Long id;
private Long informationObjectId;
private String bavicLabel;
private String bavicRole;
getters/setters, constructor, toString...
}
I have sql provider, which gnerates query String:
public class InformationObjectSqlProvider {
public String selectByInventoryNumberConditionAccountingNumber(InventoryNumberReportParamsDao reportParamsDao) {
StringBuilder sql = new StringBuilder("SELECT " +
"io.ID AS id, " +
"io.TITLE_LT AS titleLt, " +
"io.ACCOUNTING_NUMBER AS accountingNumber, " +
"io.INVENTORY_NUMBER AS inventoryNumber, " +
"io.REFERENCE_YEAR AS referenceYear, " +
"io.DURATION AS duration, " +
"cvt.NAME AS propertyRights " +
"FROM SCHEMA_ONE.INFORMATION_OBJECT io " +
"INNER JOIN SCHEMA_ONE.COPYRIGHTS c ON c.INFORMATION_OBJECT_ID = io.ID " +
"INNER JOIN SCHEMA_TWO.CLASSIFIER_VALUES cv2 ON c.PROPERTY_RIGHTS = cv2.CODE " +
"INNER JOIN SCHEMA_TWO.CLASSIFIER_VALUE_TRANSLATIONS cvt ON cv2.ID = cvt.CLASSIFIER_VALUE_ID AND cvt.LANGUAGE_ID = 1 " +
"WHERE io.INVENTORY_NUMBER = #{reportParamsDao.inventoryNumberCode} ORDER BY accountingNumber ASC");
return sql.toString();
}
}
And finally, I have created a mapper:
#Mapper
public interface InformationObjectMapper {
InformationObjectSqlProvider provider = new InformationObjectSqlProvider();
#SelectProvider(type = InformationObjectSqlProvider.class, method = "selectByInventoryNumberConditionAccountingNumber")
#Results(value = {
#Result(property = "creditsList",
column = "SCHEMA_ONE.INF_OBJ_CLASIFFIER.INFORMATION_OBJECT_ID",
javaType = Set.class, many = #Many(select = "selectCredits"))
})
List<InformationObjectMergedWithCopyrights> selectByInventoryNumberConditionAccountingNumber(#Param("reportParamsDao") InventoryNumberReportParamsDao reportParamsDao);
#Select("SELECT * FROM SCHEMA_ONE.INF_OBJ_CLASSIFIER ioc WHERE ioc.INFORMATION_OBJECT_ID = #{informationObjetId} AND ioc.\"TYPE\" = 'CREDIT' ")
#Results(value = {
#Result(property = "bavicLabel", column = "BAVIC_LABEL"),
#Result(property = "bavicRole", column = "ROLE")
})
Set<BavicCredit> selectCredits(#Param("informationObjetId") Long informationObjetId);
}
My problem is that this code doesn't return Set of BavicCredit classes. Set is always empty, just like defined in the first class. Seems like the method selectCredits isn't called at all.
The foreign key exists in the database. I believe, that I'm missing some small code or property mapping.
Java 11, Spring Boot 2.5.0, Mybatis mybatis-spring-boot-starter 2.2.0, database Oracle com.oracle.database.jdbc ojdbc8
Thanks in advance.
PS I have tried One to many relationship in MyBatis but still missing something
When using a nested select [1], the value of the column attribute should be a column name in the result set of the first query.
In the result set of your first query, the parameter to the nested query is id, so the #Result should look as follows.
#Result(
property = "creditsList",
column = "id",
javaType = Set.class,
many = #Many(select = "selectCredits"))
[1] For the basics, please read this section of the doc.
I need to pull few fields from entity class Employee and add few extra hard coded field and return the result using GROUP BY clause.
Below is the code I tried:
String query = "SELECT emp.category, emp.salary 0 as somevalue, 0 as dummy FROM employee emp "
+ "WHERE emp.date = :date AND emp.class = :class AND emp.classificationDetail.shortDescription = :classificationType GROUP BY emp.category";
TypedQuery<CustomEmployee> typQuery = entityManager.createQuery(query, CustomEmployee.class);
typQuery.setParameter("date", req.getDate());
typQuery.setParameter("class", req.getClass());
return typQuery.getResultList();
But I am getting exception that Cannot create TypedQuery for query with more than one return using requested result type.
How to achieve this.
Thanks.
First check this part: emp.salary 0 as somevalue. This should be either emp.salary as somevalue or 0 as somevalue, but not both.
Define a class like following (to keep it short; I use public properties, but you can change it if you want):
public class CustomEmployee {
public String category;
public Double salary;
public Double dummy;
...
}
The use it in the query as follows:
String query = "SELECT new mypackage.CategorySalary( " +
" emp.category, " +
" emp.salary as somevalue, " +
" 0 as dummy " +
") from ... " +
"WHERE ... ";
TypedQuery<CustomEmployee> typQuery = entityManager.createQuery(query, CustomEmployee.class);
#Value("${db.schema.name}")
private String dbSchemaName;
private final String QUERY =
"SELECT * " +
"FROM " + dbSchemaName + ".product " +
"WHERE id = :id";
I use the static String "Query" for multiple methods. The variable dbSchemaName is defined in application.properties (db.schema.name).
public List<Object> loadData(final String id){
final MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("id", id);
return jdbcTemplate.query(QUERY, parameters, new RowMapperResultSetExtractor<>(mapper)));
}
If i execute the Method loadData(...), the dbSchemaName will not be resolved.
If i change the Query from a String variable to a method, the dbSchemaName will be resolved correctly.
private final getQuery(){
"SELECT * " +
"FROM " + dbSchemaName + ".product " +
"WHERE id = :id";
}
but I want to get Access of dbSchemaName in the Query String. For me dbSchemaName is always null in the private final String QUERY. Or is there better design than making it a method?
In your non-working code sample java constructs the QUERY string before Spring has injected the value of ${db.schema.name} into dbSchemaName and it is, therefore, null.
Either stick to your method example or inject the whole query from properties:
#Value("${db.query.value}")
private String query;
Where db.query.value is:
SELECT * FROM ${db.schema.name}.product WHERE id = :id
I have got a working query, which I need to modify by filtering with constant enum value.
Now it looks this way:
public static final String venueQuery =
"select distinct v from package.Venue v "
+ "<some joins here> "
+ "WHERE v.venueType = package.enums.VenueType.VOUCHER_PROVIDER ";
Changing data this way causes
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token
Column definition is like this:
#Enumerated(EnumType.STRING)
#Column(name = "venue_type")
private VenueType venueType;
Enum definition looks this way:
public enum VenueType {
RESTAURANT, BAR, CAFE, FUN_CLUB, VOUCHER_PROVIDER
}
I am sure that other parts of query works fine, because after removing it, no exceptions are thrown.
Are there tricks for setting constant enum value in HQL query?
The preferred way would be to go about adding parameters to the query and pass the enum instance as the parameter value, but if you don't (or can't) make it a parameterized query, you can still do it with String concatenation like this:
public static final String venueQuery =
"select distinct v from package.Venue v "
+ "<some joins here> "
+ "WHERE v.venueType = '" + VenueType.VOUCHER_PROVIDER.name() +"'";
If you want it a compile time constant query String:
public static final String venueQuery =
"select distinct v from package.Venue v "
+ "<some joins here> "
+ "WHERE v.venueType = 'VOUCHER_PROVIDER'";
I am developing an application that can update my database... However, I can't get my Java method working correctly. It gives me the following error: Must declare the scalar variable "#P0WHERE". Any suggestions?
The method I am using:
public void updateTable() throws SQLException
{
Scanner input = new Scanner(System.in);
System.out.println("Update the following:\n" + this);
this.getReservationInfo(input);
DataConnection connection = new DataConnection();
String query = "UPDATE " + TableName;
query += "Set Name = ?";
query += "WHERE Person_ID = " + id;
connection.updateData(query, person_name);
connection.closeConnection();
}
Add spaces before 'SET' and 'WHERE', otherwise it will not work.
String query = "UPDATE " + TableName;
query += " SET Name = ?";
query += " , Age = ?";
query += " , Col1 = ?"; //And other cols
query += " WHERE Person_ID = " + id;
EDIT: Changed query to update multiple columns.
I think so. You seem to be missing spaces. After the TableName and after the ?.
String query = "UPDATE " + TableName;
query += " Set Name = ?"; // tableSet not good, and
// ?WHERE is not valid add spaces.
query += " WHERE Person_ID = " + id;