Custom Query from 2 tables and Spring Data JPA - spring

Exception:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [model.pojo.CarPrice]
Have 2 tables
+------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+----------------+
| car_id | int(11) | NO | PRI | NULL | auto_increment |
| car_brand | varchar(255) | NO | | NULL | |
| car_model | varchar(255) | YES | | NULL | |
| car_plate_number | varchar(255) | NO | | NULL | |
| car_type | varchar(255) | YES | | NULL | |
+------------------+--------------+------+-----+---------+----------------+
and
+---------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------+------+-----+---------+----------------+
| car_rent_details_id | int(11) | NO | PRI | NULL | auto_increment |
| cost_per_day | double | YES | | NULL | |
| rent_start_date | varchar(20) | YES | | NULL | |
| rent_end_date | varchar(20) | YES | | NULL | |
| car_info_id | int(11) | NO | UNI | NULL | |
| avaliable_to_rent | tinyint(1) | YES | | NULL | |
+---------------------+-------------+------+-----+---------+----------------+
I trying to get whole data from Car and part of CarRentDetails
in my carRepository
#Repository
public interface CarRepository extends JpaRepository<Car, Integer> {
String ALL_AVAILIABLE_CAR_LIST_PRICE = " SELECT c.car_id, c.car_brand, c.car_model,
c.car_plate_number, c.car_type, crd.cost_per_day, crd.avaliable_to_rent " +
" FROM car_info c " +
" JOIN car_rent_details crd" +
" ON c.car_id = crd.car_rent_details_id" +
" AND crd.avaliable_to_rent = true ";
#Query(value = ALL_AVAILIABLE_CAR_LIST_PRICE, nativeQuery = true)
List<CarPrice> findAllByAvaliablePrice();
Trying to map this to my POJO class:
public class CarPrice {
private Integer carId;
private String carBrand;
private String carModel;
private String carPlateNumber;
private CarType carType;
private double costPerDay;
private boolean avaliableToRent;
+ getters, setters, to string
How can I map Objects from this Query ?

Create projection interface instead of POJO
public interface CarPrice {
Integer getCarId();
String getCarBrand();
String getCarModel();
String getCarPlateNumber();
CarType getCarType();
double getCostPerDay();
boolean isAvaliableToRent();
}
And format the query that returns the fields(map with alias) that can fits the getters of projection interface
String ALL_AVAILIABLE_CAR_LIST_PRICE = " SELECT c.car_id AS carId, c.car_brand AS carBrand, c.car_model AS carModel,
c.car_plate_number AS carPlateNumber, c.car_type AS carType, crd.cost_per_day AS costPerDay, crd.avaliable_to_rent AS avaliableToRent" +
" FROM car_info c " +
" JOIN car_rent_details crd" +
" ON c.car_id = crd.car_rent_details_id" +
" AND crd.avaliable_to_rent = true ";
#Query(value = ALL_AVAILIABLE_CAR_LIST_PRICE, nativeQuery = true)
List<CarPrice> findAllByAvaliablePrice();
Hope this helps!

Related

Spring boot Jpa findAll Hibernate query returns empty

I am working on a simple personal project in order to learn SpringBoot.
Project Overview: Spring Boot aplication that gets data and inserts data through RestController endpoint into a MariaDb instance on a docker.
My MariaDb table is this:
\+------------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
\+------------------+------------+------+-----+---------+----------------+
| ACCOUNT_ID | int(11) | NO | PRI | NULL | auto_increment |
| ACCOUNT_VALUE | int(11) | YES | | 0 | |
| ACCOUNT_CURRENCY | varchar(5) | YES | | NULL | |
\+------------------+------------+------+-----+---------+----------------+
My table has data (I inserted it manualy from the terminal):
MariaDB \[dev\]\> select \* from CUSTOMER_ACCOUNT;
\+------------+---------------+------------------+
| ACCOUNT_ID | ACCOUNT_VALUE | ACCOUNT_CURRENCY |
\+------------+---------------+------------------+
| 1 | 300 | RON |
| 2 | 300 | RON |
| 3 | 300 | RON |
| 4 | 300 | RON |
| 5 | 300 | RON |
| 6 | 300 | RON |
| 7 | 300 | RON |
| 8 | 300 | RON |
| 9 | 300 | RON |
| 10 | 300 | RON |
| 11 | 300 | RON |
| 12 | 300 | RON |
| 13 | 300 | RON |
| 14 | 300 | RON |
| 15 | 300 | RON |
| 16 | 300 | RON |
| 17 | 300 | RON |
| 18 | 300 | RON |
\+------------+---------------+------------------+
My Entity class is this:
#Entity
#Table(name = "CUSTOMER_ACCOUNT", schema = "dev", catalog = "")
public class CustomerAccountEntity {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "ACCOUNT_ID")
private int accountId;
#Basic
#Column(name = "ACCOUNT_VALUE")
private Integer accountValue;
#Basic
#Column(name = "ACCOUNT_CURRENCY")
private String accountCurrency;
public int getAccountId() {
return accountId;
}
public void setAccountId(int accountId) {
this.accountId = accountId;
}
public Integer getAccountValue() {
return accountValue;
}
public void setAccountValue(Integer accountValue) {
this.accountValue = accountValue;
}
public String getAccountCurrency() {
return accountCurrency;
}
public void setAccountCurrency(String accountCurrency) {
this.accountCurrency = accountCurrency;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CustomerAccountEntity that = (CustomerAccountEntity) o;
return accountId == that.accountId && Objects.equals(accountValue, that.accountValue) && Objects.equals(accountCurrency, that.accountCurrency);
}
#Override
public int hashCode() {
return Objects.hash(accountId, accountValue, accountCurrency);
}
}
My repository class is this :
#Repository
public interface CustomerAccountRepository extends JpaRepository\<CustomerAccountEntity,Long\> {
#Query("Select ca.accountId, ca.accountValue, ca.accountCurrency from CustomerAccountEntity ca")
List<CustomerAccountEntity> findAllCA();
}
My settings is this:
# connect via localhost on port 3306
spring.datasource.url=jdbc:mariadb://localhost:3306/dev
spring.datasource.username=root
spring.datasource.password=mypass
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.datasource.driver=cdata.jdbc.mariadb.MariaDBDriver
When I hit the controller to retrieve all the data it returns empty in browser.
I attempted to play with the settings to change the driver and hibernate dialect. Note: I do have a succesfull conection to the DB
When I start the aplication there pops up a new table in mariadb
| Tables_in_dev |
+------------------+
| CUSTOMER_ACCOUNT |
| customer_account |
+------------------+
2 rows in set (0.000 sec)
Hibernate calls goes to the lower case ones, but this one is empty. It seems it is deleted when I stop the app.
I am still learning... but can someone explain what is happening.
spring.jpa.hibernate.ddl-auto=create-drop;
having this in your properties file will drop all existing content in your table each time you restart or run your spring-boot application.
To keep all records in your tables change to spring.jpa.hibernate.ddl-auto=update;
Your repo has Long as id type while entity has int. Try to make them both of the same type Long
To avoid data loss while using mariadb in docker, you should create a docker volume and plug it to /var/lib/mysql/data when you create your container

accessing inverse hasmany in controller laravel

I have three tables topics, category(HowtoCategory::class), sections(Howto::class).
Multiple categories belong to one topic and multiple sections belong to one category.
Topic Has Many Category
Category Has Many Sections
Category Belongs to Topic
Sections Belongs To Category
Topic Has Many Sections Through Category
I want to search through the sections(Howto::class) but display the related topics. How can I access topics in the controller from my query search of sections? I dont want to access it in the view but in the controller.
Controller
public function index(Request $request)
{
if (request()->filled('search')) {
request()->fullUrlWithQuery(['search ' => null]);
$sections = Howto::search($request->search)->get();
$request = $request->input('search');
} else {
$sections = null;
}
return view('howto-pages.howto-main', [
'sections' => $sections,
]);
}
Models
class Topic extends Model
{
public function categories()
{
return $this->hasMany(HowtoCategory::class);
}
public function sections()
{
return $this->hasManyThrough(Howto::class, HowtoCategory::class);
}
}
class HowtoCategory extends Model
{
public function sections()
{
return $this->hasMany(Howto::class);
}
public function topic()
{
return $this->belongsTo(Topic::class);
}
}
class Howto extends Model
{
public function category()
{
return $this->belongsTo(HowtoCategory::class);
}
}
Tables
mysql> desc howto;
+-------------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | | NULL | |
| body | mediumtext | YES | | NULL | |
| description | mediumtext | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| section_id | int | YES | | NULL | |
| howto_category_id | bigint unsigned | YES | MUL | NULL | |
+-------------------+-----------------+------+-----+---------+----------------+
mysql> desc howto_category;
+----------------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| howto_category_title | varchar(255) | NO | | NULL | |
| icon | varchar(255) | YES | | NULL | |
| description | mediumtext | YES | | NULL | |
| intro | text | YES | | NULL | |
| category_id | int | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| topic_id | bigint unsigned | YES | MUL | NULL | |
+----------------------+-----------------+------+-----+---------+----------------+
mysql> desc topics;
+-------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| topic_title | varchar(255) | NO | | NULL | |
| description | mediumtext | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-------------+-----------------+------+-----+---------+----------------+
First and foremost i'd define the foreignIDS in the relations just to make sure that are working as expected.
class Topic extends Model
{
public function categories()
{
return $this->hasMany(HowtoCategory::class);
}
public function sections()
{
return $this->hasManyThrough(
Howto::class, HowtoCategory::class,
"topic_id", "howto_category_id"
);
}
}
then you can get the Topics by searching the sections like so
use Illuminate\Database\Eloquent\Builder;
$topics = Topic::whereHas("sections", function(Builder $query) {
$query->where("howto.description", "something to search")
})->get();

Undefined binding(s) detected when compiling SELECT query

I am following a tutorial for strapi and am stuck at a part where I query for dishes belonging to a restaurant. I'm sure everything is set up properly with a one(restaurant) to many(dishes) relationship defined but the query doesn't work. I've traced it to the actual query which is:
query {
restaurant(id: "1") {
id
name
dishes {
name
description
}
}
}
which returns an error when I run it in playground. The query doesn't show any issues while I write it and doesn't allow me to write anything like:
query {
restaurant(where:{id: "1"}) {
id
name
dishes {
name
description
}
}
}
My database is mysql and the two tables look like this:
mysql> describe dishes;
+-------------+---------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+-------------------+-----------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | MUL | NULL | |
| description | longtext | YES | | NULL | |
| price | decimal(10,2) | YES | | NULL | |
| restaurant | int(11) | YES | | NULL | |
| created_at | timestamp | NO | | CURRENT_TIMESTAMP | |
| updated_at | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------------+---------------+------+-----+-------------------+-----------------------------+
7 rows in set (0.00 sec)
mysql> describe restaurants;
+-------------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+-------------------+-----------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | MUL | NULL | |
| description | longtext | YES | | NULL | |
| created_at | timestamp | NO | | CURRENT_TIMESTAMP | |
| updated_at | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------------+--------------+------+-----+-------------------+-----------------------------+
5 rows in set (0.00 sec)
These tables where auto generated by strapi.
The full error in playground is this:
{
"errors": [
{
"message": "Undefined binding(s) detected when compiling SELECT query: select `restaurants`.* from `restaurants` where `restaurants`.`id` = ? limit ?",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"restaurant"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: Undefined binding(s) detected when compiling SELECT query: select `restaurants`.* from `restaurants` where `restaurants`.`id` = ? limit ?",
" at QueryCompiler_MySQL.toSQL (/Users/redqueen/development/deliveroo/server/node_modules/knex/lib/query/compiler.js:85:13)",
" at Builder.toSQL (/Users/redqueen/development/deliveroo/server/node_modules/knex/lib/query/builder.js:72:44)",
" at /Users/redqueen/development/deliveroo/server/node_modules/knex/lib/runner.js:37:34",
"From previous event:",
" at Runner.run (/Users/redqueen/development/deliveroo/server/node_modules/knex/lib/runner.js:33:30)",
" at Builder.Target.then (/Users/redqueen/development/deliveroo/server/node_modules/knex/lib/interface.js:23:43)",
" at runCallback (timers.js:705:18)",
" at tryOnImmediate (timers.js:676:5)",
" at processImmediate (timers.js:658:5)",
" at process.topLevelDomainCallback (domain.js:120:23)"
]
}
}
}
],
"data":
Any idea why this is happening?
It seems this was a bug with the alpha.v20 and alpha.v21 versions of strapi. A bug fix has been published to solve it, an issue thread on github is here.

mysql timestamp error with time.Now() golang

How to save time.Now() in mysql table, column name as created_at timestamp null.
I am getting error :
Error:Error 1292: Incorrect datetime value: '2017-08-05 19:06:14.190 +0000' for column 'created_at' at row 1
More Information as asked :- ( I am using fragmenta cms, so all reference code with their line number is given below )
Table schema :-
mysql> describe users;
+----------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| status | int(11) | YES | | NULL | |
| role | int(11) | YES | | NULL | |
| name | varchar(250) | YES | | NULL | |
| email | varchar(250) | YES | | NULL | |
| title | varchar(250) | YES | | NULL | |
| summary | text | YES | | NULL | |
| text | text | YES | | NULL | |
| image_id | int(11) | YES | | NULL | |
| password_hash | varchar(250) | YES | | NULL | |
| password_reset_token | text | YES | | NULL | |
| password_reset_at | timestamp | YES | | NULL | |
+----------------------+--------------+------+-----+---------+----------------+
Code that is running it to save :-
At line no. 62 here ( https://github.com/fragmenta/fragmenta-cms/blob/master/src/pages/actions/setup.go#L62 )
It calls code
user := users.New()
in Line no. 51 at file here ( https://github.com/fragmenta/fragmenta-cms/blob/master/src/users/query.go#L51 )
New() function is setup.
Which is like :-
func New() *User {
user := &User{}
user.CreatedAt = time.Now()
user.UpdatedAt = time.Now()
user.TableName = TableName
user.KeyName = KeyName
user.Status = status.Draft
return user
}
and their connecting / mysql opening pattern is located here ( https://github.com/fragmenta/query/blob/master/adapters/database_mysql.go#L23 ) .
There is a bug in https://github.com/fragmenta/query. The TimeString method in query/adapters/database.go is not valid for all DBMS adapters.
// TimeString - given a time, return the standard string representation
func (db *Adapter) TimeString(t time.Time) string {
return t.Format("2006-01-02 15:04:05.000 -0700")
}
It's not valid for a MySQL timestamp: MySQL 5.7 Reference Manual, 11.3.1 The DATE, DATETIME, and TIMESTAMP Types. The MySQL TimeString method in query/adapters/database_mysql.go should be:
// TimeString - given a time, return the MySQL standard string representation
func (db *MysqlAdapter) TimeString(t time.Time) string {
return t.Format("2006-01-02 15:04:05.999999")
}
You are trying to insert it using a string query.go:36:
now := query.TimeString(time.Now().UTC())
that is generated by the package that you are using database.go:59:
return t.Format("2006-01-02 15:04:05.000 -0700")
MySQL expects it to be in the pattern of yyyy-MM-dd hh:mm:ss, use the following snippet to apply the pattern to you current Time.time object:
now := time.Now().UTC().Format("2006-01-02 03:04:05")
Anyway, why not to use the SQL function NOW() when inserting the record ?

Return filtered records from a returned set of data from two tables

I have three tables:
- Venue
- Space (belongs to Venue)
- Included Space (belongs to Space)
I receive the id of a Venue in the route and return all the related spaces that I know have Included Spaces(a field called num_included_spaces__c on the Space record that maintains a count of its children). Now that I have all the related parent Spaces for that Venue, I need to find all of the Included Spaces for them.
An Included Space is still a Space, it just happens to have a parent that resides in the same table. I'm trying to turn this:
Venue = Rockdog
- Space = Upstairs
- Space = Media Room
- Space = Courtyard
- Space = Downstairs
- Space = Front Patio
- Space = Indoor Bar
Into this:
Venue = Rockdog
- Space = Upstairs
-- Included Space = Media Room
-- Included Space = Courtyard
- Space = Downstairs
-- Included Space = Front Patio
-- Included Space = Indoor Bar
The Included Spaces table has belongs_to__c and space__c as fields, where belongs_to__c is the id of the parent space and space__c is the id of the child. So i'm looking to find all the Included Spaces where belongs_to_c matches the id of any #spaces returned below
#sub_spaces = Space.where("venue__c = ? AND num_included_spaces__c = ?", params[:venue],0)
#spaces = Space.where("venue__c = ? AND num_included_spaces__c > ?", params[:venue],0)
How would I write this Active Record Query for #included_spaces?
my database schema.
mysql> describe venues;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
4 rows in set (0,00 sec)
mysql> describe spaces;;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| venue_id | int(11) | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
5 rows in set (0,00 sec)
ERROR:
No query specified
mysql> describe included_spaces;;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| space_id | int(11) | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
5 rows in set (0,00 sec)
ERROR:
No query specified
Below function will somehow give you the result you need (in console ofcourse ) however it's not a good solution - it queries database more than needed. However it is the easy -))
def foo id
v = Venue.find(id)
puts v.name
v.spaces.each do |space|
puts space.name
space.included_spaces.each do |spis|
puts spis.name
end
end
end
You can also try a more complex query sth like,
mysql> SELECT spaces.name, included_spaces.name FROM `spaces` INNER JOIN `venues` ON `venues`.`id` = `spaces`.`venue_id` INNER JOIN `included_spaces` ON `included_spaces`.`space_id` = `spaces`.`id` WHERE `spaces`.`venue_id` = 1
-> ;
+------------+-----------+
| name | name |
+------------+-----------+
| Upstairs, | Front |
| Upstairs, | Patio, |
| Upstairs, | Indoor |
| Upstairs, | Bar |
| Downstairs | Media |
| Downstairs | Room, |
| Downstairs | Courtyard |
+------------+-----------+
7 rows in set (0,00 sec)
which should be translated to active record as
Space.joins(:venue)
.joins(:included_spaces)
.where(venue_id: 1)
.select('spaces.name, included_spaces.name')

Resources