How to use mybatis mappers (without type handlers) for fetching DB nested collections from a stored procedure.
eg: the stored procedure returns a DB table object of the following type :
TYPE class_list IS TABLE OF class ;
where
TYPE class AS OBJECT (students student_list, class_teacher teacher);
TYPE student_list IS TABLE OF student;
TYPE student AS OBJECT (name VARCHAR2, age NUMBER, marks NUMBER);
TYPE teacher AS OBJECT (name VARCHAR2, qualification VARCHAR2, phone_number NUMBER);
#blackwizard, you are correct. For custom DB types, a custom type handler is a must. Here is the syntax (jdbcTypeName) to tell mybatis that it is dealing with a custom object:
{call YOUR_PACKAGE.YOUR_PROCEDURE(
#{your_input_parameter, jdbcType=VARCHAR mode=IN javaType=java.lang.String mode=IN },
#{your_output_parameter, jdbcType=ARRAY mode=OUT jdbcTypeName=class_list typeHandler=custom_typeHandler})}
Note: This is not supported in the deprecated parameterMap.
Related
I have a seq 'user_tfa_info_seq' which I want to use in 'user_tfa_info' table in Gorm Model.
I used the following structure, but it does not work.
type UserTfaInfo struct{
ID uint `gorm:"primary_key;type:bigint(20) not null" sql:"nextval('user_tfa_info_seq')"`
}
My struct looks like:
type AdvertContent struct {
Id string `gorm:"column:id;primaryKey;type:uuid;default:uuid_generate_v4()" json:"id" example:"4ff8eb91-640b-4e26-a50f-3bcd1f933d0c"`
FromTime *time.Time `gorm:"column:from_time;type:time;" json:"fromTime,omitempty" example:"HH:MM"`
ToTime *time.Time `gorm:"column:to_time;type:time;" json:"toTime,omitempty" example:"HH:MM"`
} //#name AdvertContent
func (this AdvertContent) TableName() string {
return "advert_content"
}
When I use gorm.AutoMigrate, table fields from_time and to_time created with type timestampz, not time.
Gorm debug mode:
CREATE TABLE "advert_content" ("id" uuid DEFAULT uuid_generate_v4(),"from_time" timestamptz,"to_time" timestamptz)
How can I create table with time type fields?
when using specified database data type, it needs to be a full
database data type, for example: MEDIUMINT UNSIGNED NOT NULL
AUTO_INCREMENT
You should use the database data type like this
I have a JPA/Hibernate entity which has a JSONB column (using https://github.com/vladmihalcea/hibernate-types ) for storing a list of strings. This works fine so far.
#TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
#Type(type = "jsonb")
#Column(name = "TAGS", columnDefinition = "jsonb")
private List<String> tags;
Now I want to check if another string is contained in the list of strings.
I can do this by writing a native query and use the #> operator from Postgres. Because of other reasons (the query is more complex) I do not want to go in that direction. My current approach is calling the jsonb_contains method in a Spring Data specification (since the operator is just alias to this function), e.g. jsonb_contains('["tag1", "tag2", "tag3"]','["tag1"]'). What I am struggling with is, getting the second parameter right.
My initial approach is to also use a List of Strings.
public static Specification<MyEntity> hasTag(String tag) {
return (root, query, cb) -> {
if (StringUtils.isEmpty(tag)) {
return criteriaBuilder.conjunction();
}
Expression<Boolean> expression = criteriaBuilder.function("jsonb_contains",
Boolean.class,
root.get("tags"),
criteriaBuilder.literal(List.of(tag)));
return criteriaBuilder.isTrue(expression);
};
}
This results in the following error.
Caused by: org.postgresql.util.PSQLException: ERROR: function jsonb_contains(jsonb, character varying) does not exist
Hinweis: No function matches the given name and argument types. You might need to add explicit type casts.
Position: 375
It does know that root.get("tags") is mapped to JSONB but for the second parameter it does not. How can I get this right? Is this actually possible?
jsonb_contains(jsob, jsonb) parameters must be jsonb type.
You can not pass a Java String as a parameter to the function.
You can not do casting in Postgresql via JPA Criteria.
Using JSONObject or whatever does not help because Postgresql sees it as
bytea type.
There are 2 possible solutions:
Solution 1
Create jsonb with jsonb_build_object(text[]) function and send it to jsonb_contains(jsonb, jsonb) function:
public static Specification<MyEntity> hasTag(String tag) {
// get List of key-value: [key1, value1, key2, value2...]
List<Object> tags = List.of(tag);
// create jsonb from array list
Expression<?> jsonb = criteriaBuilder.function(
"jsonb_build_object",
Object.class,
cb.literal(tags)
);
Expression<Boolean> expression = criteriaBuilder.function(
"jsonb_contains",
Boolean.class,
root.get("tags"),
jsonb
);
return criteriaBuilder.isTrue(expression);
}
Solution 2
Create custom function in your Postgresql and use it in Java:
SQL:
CREATE FUNCTION jsonb_contains_as_text(a jsonb, b text)
RETURNS BOOLEAN AS $$
SELECT CASE
WHEN a #> b::jsonb THEN TRUE
ELSE FALSE
END;$$
LANGUAGE SQL IMMUTABLE STRICT;
Java Code:
public static Specification<MyEntity> hasTag(String tag) {
Expression<Boolean> expression = criteriaBuilder.function(
"jsonb_contains_as_text",
Boolean.class,
root.get("tags"),
criteriaBuilder.literal(tag)
);
return criteriaBuilder.isTrue(expression);
}
I think that the reason is that you pass the varchar as the second param. jsonb_contains() requires two jsonb params.
To check a jsonb array contains all/any values from a string array you need to use another operators: ?& or ?|.
The methods bindings for them in PSQL 9.4 are: jsonb_exists_all and jsonb_exists_any correspondingly.
In your PSQL version, you could check it by the following command:
select * from pg_operator where oprname = '?&'
I have a numeric(10,2) data type column named "Value" in a Payment table in postgresql Database.
CREATE TABLE IF NOT EXISTS PAYMENT(
PAYMENT_ID BIGINT NOT NULL DEFAULT nextval('payment_seq') PRIMARY KEY,
DATE TIMESTAMP,
PLACE VARCHAR(255),
VALUE NUMERIC(10,2) NOT NULL,
UTILISATEUR_ID BIGINT REFERENCES UTILISATEUR
);
I want to retrieve that numeric value by a BigDecimal Data Type in Java. (dto)
import java.math.BigDecimal;
public interface UserSumByGroup {
public String getFullName();
public BigDecimal getSumOfValues();
}
For some reason all the times the return values for the dto is null when I execute in the controller..
...
List<UserSumByGroup> usersGroupSumPaymnt = userRepo.userGroupSumPaymt();
model.addAttribute("userGroupListSumPaymt", usersGroupSumPaymnt);
System.out.println("usersGroupSumPaymnt=> "+usersGroupSumPaymnt.get(0).getSumOfValues());
...
SQL Query:
SELECT usr.FULL_NAME as fullName, SUM(VALUE) as paymentCount
FROM PAYMENT pym left join UTILISATEUR usr ON usr.utilisateur_id = pym.utilisateur_id
WHERE MONTH(pym.date) = MONTH(CURRENT_DATE)
AND YEAR(pym.date) = YEAR(CURRENT_DATE)
AND pym.utilisateur_id IN (1,5)
GROUP BY pym.utilisateur_id, usr.FULL_NAME;
Console Log:
usersGroupSumPaymnt=> null
Do you have some idea why I got always a Null?.
Thanks.
To correspond the names of the variables between Spring JPA and the Database, the names of the attributes of the dto object must be the same to the name of the result field in the query.
The name of the result query "paymentCount" needs to be the same as the dto instance "sumOfValues".
So, Change:
SUM(VALUE) as paymentCount
By
SUM(VALUE) as sumOfValues
I have the following (Grails) domain object:
class Country {
Integer id
char country_abbr
String country_name
static mapping = {
version false
id name: 'id'
table 'country'
id generator:'identity', column:'id'
}
static constraints = {
}}
The 'country_abbr' field within the 'country table' has type: character(2). However, whenever I am setting the domain object's data type (for 'country_abbr') to String, initialization is failing with the following exception
org.hibernate.HibernateException: Wrong column type in mydb.country for column country_abbr. Found: bpchar, expected: varchar(255)
On the other hand, leaving this type as a Java char would only retrieve the first character. Any ideas how may I map to this type? Also, what is bpchar exactly?
Thanks
Just to make this question answered. The solution is to change the country_abbr mapping:
country_abbr columnDefinition: 'char'
Reference here.