mybatis batchInsertSelective can not batch return primary key(id) - mybatis

use mybatis batchInsertSelective can not batch return primary key(id), but use batchInsert can batch return, use batchInsertSelective can only return first primary key(id). why?

Related

Generate "GENERATED ALWAYS AS IDENTITY" With Spring JPA for PostgreSQL

Is it possible to get Spring-Data-JPA to generate PRIMARY KEY column with GENERATED ALWAYS AS IDENTITY.
class SomeClass {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private ID id;
...
}
The result obtained with javax.persistence.* library is:
CREATE TABLE IF NOT EXISTS public.sometable
(
id bigint NOT NULL DEFAULT nextval('sometable_id_seq'::regclass),
...
CONSTRAINT sometable_pkey PRIMARY KEY (id)
...
);
However, the ideal code would be:
CREATE TABLE IF NOT EXISTS public.sometable (
id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY
...
);
Is there a directive to tell Spring Data to generate GENERATED ALWAYS AS IDENTITY with PostgreSQL?
No, it’s not possible. Have tested with columnDefinition, and it either produces an exception or an invalid DDL. Have a nice day :)

SQLAlchemy + asyncpg doesn't catch deferred exception

I am now using SQLAlchemy 1.4, asyncpg and FastAPI, and I wrote the code like this:
try:
cr: sa.engine.CursorResult = await conn.execute(stmt)
return schemas.UserGroup(
**user_group_dict,
id=cr.inserted_primary_key[0],
)
except sa.exc.IntegrityError:
raise exceptions.conflict_exception()
UserGroup table references User and Group tables and has a unique key constraint (user, group)
user_groups = sa.Table(
"auth_user_groups",
metadata,
sa.Column(
"id",
sa.BigInteger,
primary_key=True,
index=True,
),
sa.Column(
"user_id",
sa.BigInteger,
sa.ForeignKey("auth_user.id"),
),
sa.Column(
"group_id",
sa.BigInteger,
sa.ForeignKey("auth_group.id"),
),
sa.UniqueConstraint("user_id", "group_id"),
)
CREATE TABLE IF NOT EXISTS public.auth_user_groups
(
id bigint NOT NULL DEFAULT nextval('auth_user_groups_id_seq'::regclass),
user_id integer NOT NULL,
group_id integer NOT NULL,
CONSTRAINT auth_user_groups_pkey PRIMARY KEY (id),
CONSTRAINT auth_user_groups_user_id_group_id_94350c0c_uniq UNIQUE (user_id, group_id),
CONSTRAINT auth_user_groups_group_id_97559544_fk_auth_group_id FOREIGN KEY (group_id)
REFERENCES public.auth_group (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED,
CONSTRAINT auth_user_groups_user_id_6a12ed8b_fk_auth_user_id FOREIGN KEY (user_id)
REFERENCES public.auth_user (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED
)
When I try to insert a duplicated record, it works fine.
However, when I try to insert a record with fk which does not exist in User and Group, I cannot catch the exception.
2022-06-14 01:02:50,978 INFO sqlalchemy.engine.Engine COMMIT
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/home/test/projects/fastapi-from-dj/venv/lib/python3.10/site-packages/uvicorn/protocols/http/h11_impl.py", line 366, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "/home/test/projects/fastapi-from-dj/venv/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
return await self.app(scope, receive, send)
...
File "/home/test/projects/fastapi-from-dj/venv/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 685, in do_commit
dbapi_connection.commit()
File "/home/test/projects/fastapi-from-dj/venv/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 741, in commit
self._handle_exception(error)
File "/home/test/projects/fastapi-from-dj/venv/lib/python3.10/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 682, in _handle_exception
raise translated_error from error
sqlalchemy.exc.IntegrityError: (sqlalchemy.dialects.postgresql.asyncpg.IntegrityError) <class 'asyncpg.exceptions.ForeignKeyViolationError'>: insert or update on table "auth_user_groups" violates foreign key constraint "auth_user_groups_user_id_6a12ed8b_fk_auth_user_id"
DETAIL: Key (user_id)=(15) is not present in table "auth_user".
(Background on this error at: https://sqlalche.me/e/14/gkpj)
Of course, I tried to catch exception with asyncpg.exceptions.ForeignKeyViolationError and Exception as e, but I failed.
Thank you.
Thanks to #Gord Thompson's comment
I was able to solve my problem by altering the table FK constraints:
ALTER TABLE IF EXISTS public.auth_user_groups
DROP CONSTRAINT auth_user_groups_user_id_6a12ed8b_fk_auth_user_id;
ALTER TABLE IF EXISTS public.auth_user_groups
ADD CONSTRAINT auth_user_groups_user_id_6a12ed8b_fk_auth_user_id FOREIGN KEY (user_id)
REFERENCES public.auth_user (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
NOT DEFERRABLE;
As a result, now I have a table like this:
CREATE TABLE IF NOT EXISTS public.auth_user_groups
(
id bigint NOT NULL DEFAULT nextval('auth_user_groups_id_seq'::regclass),
user_id integer NOT NULL,
group_id integer NOT NULL,
CONSTRAINT auth_user_groups_pkey PRIMARY KEY (id),
CONSTRAINT auth_user_groups_user_id_group_id_94350c0c_uniq UNIQUE (user_id, group_id),
CONSTRAINT auth_user_groups_group_id_97559544_fk_auth_group_id FOREIGN KEY (group_id)
REFERENCES public.auth_group (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT auth_user_groups_user_id_6a12ed8b_fk_auth_user_id FOREIGN KEY (user_id)
REFERENCES public.auth_user (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
It does not have the line: DEFERRABLE INITIALLY DEFERRED
I am now using the tables which were migrated by Django so that FastAPI uses them as a REST API.
I believe that the following answer link will be useful for Django users:
How can I set a table constraint "deferrable initially deferred" in django model?
Thank you.

R2DBC: Why are RowsFetchSpec<T> operators (.all(),.first(),.one()) signal onComplete although record is stored in database?

I am using DatabaseClient for building a custom Repository. After I insert or update an Item I need that Row data to return the saved/updated Item. I just can´t wrap my head around why .all(), .first(), .one() are not returning the Result Map, although I can see that the data is inserted/updated in the database. They just signal onComplete. But .rowsUpdated() returns 1 row updated.
I observed this behaviour with H2 and MS SQL Server.
I´m new to R2dbc. What am I missing? Any ideas?
#Transactional
public Mono<Item> insertItem(Item entity){
return dbClient
.sql("insert into items (creationdate, name, price, traceid, referenceid) VALUES (:creationDate, :name, :price, :traceId, :referenceId)")
.bind("creationDate", entity.getCreationDate())
.bind("name", entity.getName())
.bind("price", entity.getPrice())
.bind("traceId", entity.getTraceId())
.bind("referenceId", entity.getReferenceId())
.fetch()
.first() //.all() //.one()
.map(Item::new)
.doOnNext(item -> LOGGER.info(String.format("Item: %s", item)));
}
The table looks like this:
CREATE TABLE [dbo].[items](
[creationdate] [bigint] NOT NULL,
[name] [nvarchar](32) NOT NULL,
[price] [int] NOT NULL,
[traceid] [nvarchar](64) NOT NULL,
[referenceid] [int] NOT NULL,
PRIMARY KEY (name, referenceid)
)
Thanks!
This is the behavior of an insert/update statement in database, it does not return the inserted/updated rows.
It returns the number of inserted/updated rows.
It may also return some generated values by the database (such as auto increment, generated uuid...), by adding the following line:
.filter(statement -> statement.returnGeneratedValues())
where you may specify specific generated columns in parameter. However this has limitations depending on the database (for example MySql can only return the last generated ID of an auto increment column even if you insert multiple rows).
If you want to get the inserted/updated values from database, you need to do a select.

Laravel 5.3 Eloquent transactions and foreign key restrictions

Am working on bigger project where we have multiple schemas in one Postgres DB. We have created foreign keys between schemas. Here is an example >
We have company schema and user schema. Company schema has company_users table which have foreign key restriction on user.users table
CREATE TABLE company.company_user
(
id serial NOT NULL,
company_id integer NOT NULL,
user_id integer NOT NULL,
created_at timestamp(0) without time zone,
updated_at timestamp(0) without time zone,
deleted_at timestamp(0) without time zone,
CONSTRAINT company_user_pkey PRIMARY KEY (id),
CONSTRAINT company_user_company_id_foreign FOREIGN KEY (company_id)
REFERENCES company.companies (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT company_user_user_id_foreign FOREIGN KEY (user_id)
REFERENCES "user".users (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
Following queries run in Postgres without issue
BEGIN;
insert into "db"."user"."users" (id,"surname", "firstname", "email", "position", "language_id", "is_super_admin", "updated_at", "created_at") values (156,'Mueller', 'Julianne', 'julianne.mueller1#example.org', 'Nuclear Power Reactor Operator', 41, false, '2017-01-13 12:35:10', '2017-01-13 12:35:10') returning "id";
insert into "db"."company"."company_user" ("company_id", "user_id", "updated_at", "created_at") values (4445, 156, '2017-01-13 12:35:10', '2017-01-13 12:35:10') returning "id";
COMMIT;
However if i perform same queries via Eloquent in Laravel
\DB::beginTransaction();
$user = new User(["surname" => 'Mueller',
"firstname" => 'Julianne',
"email" => 'julianne.mueller1#example.org',
"position" => 'Nuclear Power Reactor Operator',
"language_id" => 41,
"is_super_admin" => false]
);
if (!$user->save()) {
\DB::rollBack();
return false;
}
\Log::error($user->id);
$company_user = new CompanyUser([
"company_id" => 4445,
"user_id" => $user->id
]);
if (!$company_user->save()) {
\DB::rollBack();
return false;
}
\DB::commit();
is throwing folloing error (it seems that it cannot find id of user in the table)
PDOException: SQLSTATE[23503]: Foreign key violation: 7 ERROR: insert or update on table "company_user" violates foreign key constraint "company_user_user_id_foreign"
Would anyone can say why this is not working? \Log::error($user->id) is printing id of inserted user. I tried to print out queries from Laravel with DB listener, all queries are executed in correct order, but am still getting this error.
Ok so we found a solution. It seems that we need to start transaction for each of schemas separately + each foreign key that are referencing different schema than their own should be created as deferred.
Make sure CompanyUser has $fillable:
$fillable = ['user_id', 'company_id'];
Also, make sure there is a user with this ID is already in users table. Maybe you'll need to get rid of transaction.

ADO.NET entity data model deleting many rows

I have following structure of the database
CREATE TABLE IF NOT EXISTS `klienci` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nazwa` varchar(50) NOT NULL,
`miejscowosc` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `klienci_do_trasy` (
`klient_id` int(11) NOT NULL,
`trasa_id` int(11) NOT NULL,
`seq` int(11) NOT NULL,
PRIMARY KEY (`klient_id`,`trasa_id`),
KEY `trasa_id` (`trasa_id`),
KEY `klient_id` (`klient_id`,`trasa_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `trasy` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nazwa` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
ALTER TABLE `klienci_do_trasy`
ADD CONSTRAINT `klienci_do_trasy_ibfk_5` FOREIGN KEY (`klient_id`) REFERENCES `klienci` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `klienci_do_trasy_ibfk_6` FOREIGN KEY (`trasa_id`) REFERENCES `trasy` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;
And I would like to run query similar to:
DELETE FROM klienci_do_trasy WHERE klient_id = 1;
Don't know how to do this with ADO.NET entity
With EntityFramework v1.0 there is no such a possibility. You would have to call ObjectContext.DeleteObject for each entity:
using (TheDataContext entities = new TheDataContext())
{
List<Klienci_do_tracy> kdcList = //get entities to delete
foreach(Klienci_do_tracy kdc in kdcList)
{
entities.DeleteObject(kdc);
}
entities.SaveChanges();
}
or you could use EntityCommand to do that on old fashion way.
[update: run native sql with EF]
var eConnection = (System.Data.EntityClient.EntityConnection)yourContextInstance.Connection;
DbConnection conn = eConnection.StoreConnection;
if (conn.State != ConnectionState.Open)
conn.Open();
using (DbCommand cmd = conn.CreateCommand())
{
//write native sql query
cmd.CommandText = "delete from...where...";
cmd.ExecuteNonQuery();
}
You would probably have to wrap this in try finally to ensure closing connection if something goes wrong and additional checks on connestion state.