I have this error:
duplicate key value violates unique constraint "HDPL_COMPOSANT_pkey"
Détail : Key (composant_id)=(766975) already exists.
nextVal is superior to MAX(composantId) so why does it show this error?
#Entity
#Table(name= ""HDPL_COMPOSANT"",schema="hdpl")
public class ComposantEntity implements java.io.Serializable {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="composant_id2")
#SequenceGenerator(
name="composant_id2",
sequenceName="\"HDPL_COMPOSANT_composant_id_seq\""
)
#Column(name="composant_id", unique=true, nullable=false)
private int composantId;
#Column(name="code_app", nullable=false)
private String codeApp;
#Column(name="libelle_app", nullable=false)
private String libelleApp;
#Transient
private String typeModule;
CREATE SEQUENCE HDPL_COMPOSANT_composant_id_seq;
CREATE TABLE hdpl."HDPL_COMPOSANT"
(
code_app character varying COLLATE pg_catalog."default" NOT NULL,
libelle_app character varying COLLATE pg_catalog."default" NOT NULL,
composant_id integer NOT NULL default nextval ('HDPL_COMPOSANT_composant_id_seq'::regclass),
CONSTRAINT hdpl_composant_pk PRIMARY KEY (composant_id)
) WITHOUT OIDS;
It crashes when i call this method
#Override
public void createComposant(String codeApp, String libelleApp) {
ComposantEntity composantEntity = new ComposantEntity();
composantRepo.deleteByCodeAppAndLibelleApp(codeApp, libelleApp);
composantEntity.setCodeApp(codeApp);
composantEntity.setLibelleApp(libelleApp);
composantRepo.save(composantEntity);
}
when i try to save my composantEntity it crashes showing the error above
My question is why my Id doesnt take nextVal and take an other value that already exists
am trying to migrate to JPA this method here s the ancient code that i tried to change using the method above
#Override
#MethodLog(logLevel = StandardLevel.DEBUG)
public long createComposant(String codeApp, String libelleApp) {
final KeyHolder idHolder = new GeneratedKeyHolder();
final SqlParameterSource params = new MapSqlParameterSource().addValue(CODE_APP, codeApp).addValue(LIBELLE_APP,
libelleApp);
// suppression des anciens
jdbcTemplate.update(DELETE_COMPOSANT, params);
// creation des nouveaux
jdbcTemplate.update(CREATE_COMPOSANT, params, idHolder, new String[] { "composant_id" });
return idHolder.getKey().longValue();
}
Related
I created a database with sqflite in Flutter. When I try to insert data I get the error
error DatabaseException(near ")": syntax error (code 1 SQLITE_ERROR): , while compiling: CREATE TABLE nutritionTable(
_id INTEGER PRIMARY KEY,
calories INTEGER NOT NULL,
carbs INTEGER NOT NULL,
fat INTEGER NOT NULL,
protein INTEGER NOT NULL,
))
My code to create a table looks like this:
static final _dbName = 'userNutritionSql.db';
static final _dbVersion = 1;
static final _tableName = 'nutritionTable';
static final columnId = '_id';
static final columnCalories = 'calories';
static final columnCarbs = 'carbs';
static final columnFat = 'fat';
static final columnProtein = 'protein';
Future _onCreate(Database db, int version) async{
final idType = 'INTEGER PRIMARY KEY';
final intType = 'INTEGER NOT NULL';
await db.execute(
'''
CREATE TABLE $_tableName(
$columnId $idType,
$columnCalories $intType,
$columnCarbs $intType,
$columnFat $intType,
$columnProtein $intType,
)
'''
);
}
I cant spot the syntax error, does anyone has an idea whats wrong?
Laravel: 7; PHP: 7.4/8.0
In my project I have two related models: User and TimeAccount. Both use UUID for their primary key, the key name is still id.
Migrations:
class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->uuid('id')->primary();
// snip...
});
}
// snip...
}
class CreateTimeAccountsTable extends Migration
{
public function up()
{
Schema::create('time_accounts', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->foreignUuid('user_id')->nullable()->constrained();
// snip...
});
}
// snip...
}
Models:
class User
{
use IsIdentifiedByUuid;
protected $keyType = 'string';
public function timeAccount()
{
return $this->hasOne(TimeAccount::class);
}
// snip...
}
class TimeAccount
{
use IsIdentifiedByUuid;
protected $keyType = 'string';
public function user()
{
return $this->belongsTo(User::class);
}
// snip...
}
IsIdentifiedByUuid Trait:
trait IsIdentifiedByUuid
{
protected static function bootIsIdentifiedByUuid()
{
static::creating(fn ($model) => static::isIdentifiedByUuidCreatingHandler($model));
static::saving(fn ($model) => static::isIdentifiedByUuidSavingHandler($model));
}
public function initializeIsIdentifiedByUuid()
{
$this->keyType = 'string';
}
protected function getUuidColumn(): string
{
return property_exists($this, 'uuid_column') ? $this->uuid_column : 'id';
}
protected static function getNewUuid(): UuidInterface
{
$columnName = app(static::class)->getUuidColumn();
$tableName = app(static::class)->getTable();
$columnDescriptor = "$tableName.$columnName";
$uuid = "";
$query = \DB::table($tableName)
->select($columnDescriptor)
->where($columnDescriptor, $uuid);
$attempts = 0;
do {
if ($attempts >= \App\Constants\Uuid::MAX_ATTEMPTS) {
throw new UuidMaxGeneratorAttemptsExceededException();
}
$uuid = Str::uuid();
$attempts++;
} while ($query->setBindings([ $uuid->toString() ])->count() > 0);
return $uuid;
}
/**
* Handles the creation of a model.
* - Generates new UUID if the UUID column is empty and auto-increment is enabled
*
* #param Model $model
* #throws \App\Exceptions\UuidMaxGeneratorAttemptsExceededException
*/
protected static function isIdentifiedByUuidCreatingHandler(Model $model)
{
$columnName = $model->getUuidColumn();
if ($model->getIncrementing() && !$model->{$columnName}) {
$uuid = static::getNewUuid();
\Log::debug(
"IsIdentifiedByUuid [CREATING]:" .
" Generating new UUID for `" . get_class($model) . ": $uuid`"
);
$model->{$columnName} = $uuid->toString();
} else {
\Log::debug(
"IsIdentifiedByUuid [CREATING]:" .
" Using existing UUID for `" . get_class($model) . ": $model->{$columnName}`"
);
}
}
/**
* Handles the saving of a Model.
* - Prevents changes to the UUID column
* - Rolls back changed value to old value
*
* #param Model $model
*/
protected static function isIdentifiedByUuidSavingHandler(Model $model)
{
$columnName = $model->getUuidColumn();
$originalUuid = $model->getOriginal($columnName);
if (!is_null($originalUuid) &&
$originalUuid !== $model->{$columnName}
) {
\Log::debug(
"IsIdentifiedByUuid [SAVING]:" .
" Prevented change of UUID for `" . get_class($model) . ":$originalUuid`"
);
$model->{$columnName} = $originalUuid;
}
}
}
Now the Problem:
Within an user-observer on the created hook I'm doing this:
$userTimeAccount = $user->timeAccount()->create([
// snip...
]);
So far - before switching to UUID instead of integer keys - everything worked fine! As far as I know creating the related model before the user-model has been saved (and obviously before auto-inc was triggered) is something that is explicitly allowed by eloquent/Laravel (though I can not find the section of the docs).
After switching to UUID this is not working anymore and I'm getting an SQL error:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (laravel_torus.time_accounts, CONSTRAINT time_accounts_user_id_foreign FOREIGN KEY (user_id) REFERENCES users (id)) (SQL: insert into time_accounts (time_account_type_id, balance, borrow, user_id, id, updated_at, created_at) values (3, 0, 0, 0, a995807b-b7e1-4af3-96de-7c48187f943d, 2021-07-09 12:54:25, 2021-07-09 12:54:25))
SQL beautified:
insert into `time_accounts`
(`time_account_type_id`, `balance`, `borrow`, `user_id`, `id`, `updated_at`, `created_at`)
values
(3, 0, 0, 0, 'bad86e70-7496-4b42-b2a1-5cc3c5a4d06c', '2021-07-09 11:19:17', '2021-07-09 11:19:17');
Somehow Laravel tries to insert zero (integer) for the Foreign key which will obviously not work. I even tried setting keyType to 'string' manually without effect.
Where am I wrong?
EDIT: It seems like there is a race condition. The created hook of the Observer will be triggered before the created hook of the User model. This leads to the missing ID - the ID is present when using integer and auto increment, just as it should.
TL;DR
I was not able to solve this with MySQL and switched to Postgres SQL.
DONT USE UUID WITH MYSQL unless you are, absolutely sure that: 1. you need to and 2. the performance impact will be negligible!
I really can not explain how this error is happening at all. The ID in question already exists (looking with the debugger into the $attribnutes array of the model), still Laravel will return integer 0 when calling $user->id.
While investigating the problem I noticed that Laravel is creating String columns for the UUID instead of binary (wich is what I would have expected). Since string comparism is quite cost intensive compared to integer/binary comparism I decided to abandon MySQL. UUID's are mandatory for this project and a shift to another DBMS, away from MySQL, in future was already intended.
Postgres SQL supports a special Column type uuid wich will be used by Laravel if a UUID column is defined. This does not only store and compare the ID as binary but also checks for format and unique values, meaning you can not enter an invalid UUID by accident like in MySQL regular sting columns wich seem to have no checks at all apart from not null and unique.
This question already has an answer here:
Syntax error due to using a reserved word as a table or column name in MySQL
(1 answer)
Closed 8 years ago.
I tried adding new class to my application. Everything was fine, until I added Boolean read. When I add it to my class, I get:
We got the following error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'read tinyint(1) default 0, constraint ck_event_type check (' at line 7 [ERROR:1064, SQLSTATE:42000], while trying to run this SQL script:
and the important part of the script:
create table event (
id bigint auto_increment not null,
type varchar(14) not null,
user_id bigint,
message varchar(255) not null,
date date,
read tinyint(1) default 0,
constraint ck_event_type check (type in ('game_started','game_completed','wrong_answer','correct_answer','wrong_location')),
constraint pk_event primary key (id))
I have no idea what's the problem. I have Boolean declared in other class and there is no problem. I'm using play 2.2.1
My class:
package models;
import java.sql.Date;
import java.util.*;
import javax.persistence.*;
import play.db.ebean.*;
import com.avaje.ebean.*;
import play.data.validation.Constraints.*;
#Entity
public class Event extends Model{
#Id
public Long id;
#Enumerated(EnumType.STRING)
#Column(nullable = false)
public EVENT_TYPE type;
#ManyToOne
public User user;
#Column
public Date date;
#Column(nullable = false)
public String message;
#Column
public Boolean read;
public Event(User user, String message, EVENT_TYPE type, Date date) {
//this.user = user;
//this.message = message;
//this.type = type;
//this.date = date;
//read = false;
}
}
read is a reserved keyword in MySql. Try naming that column something else.
Reserved Words in MySQL 5.7
I've configured with hibernate-search annotation (4.1.1 version library) my class Intervento. So, I'm using jpa and in my case i can omit #DocumentId but I have a composite primary key...
#IdClass(it.domain.InterventoPK.class)
#Entity
#Indexed
#AnalyzerDef(name = "interventongram", tokenizer = #TokenizerDef(factory = StandardTokenizerFactory.class),
filters = {
#TokenFilterDef(factory = LowerCaseFilterFactory.class),
#TokenFilterDef(factory = StopFilterFactory.class, params = {
#Parameter(name = "words", value = "lucene/dictionary/stopwords.txt"),
#Parameter(name = "ignoreCase", value = "true"),
#Parameter(name = "enablePositionIncrements", value = "true")
}),
#TokenFilterDef(factory = ItalianLightStemFilterFactory.class),
#TokenFilterDef(factory = SynonymFilterFactory.class, params = {
#Parameter(name = "synonyms", value = "lucene/dictionary/synonyms.txt"),
#Parameter(name = "expand", value = "true")
}),
#TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = {
#Parameter(name = "language", value = "Italian")
})
})
#Table(name = "intervento", catalog = "gestionale")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(namespace = "Clinigo/it/domain", name = "Intervento")
#XmlRootElement(namespace = "Clinigo/it/domain")
public class Intervento implements Serializable {
private static final long serialVersionUID = 1L;
/**
*/
#Column(name = "idintervento", nullable = false)
#Basic(fetch = FetchType.EAGER)
#Id
#XmlElement
Integer idintervento;
/**
*/
#Column(name = "lingua_idlingua", nullable = false)
#Basic(fetch = FetchType.EAGER)
#Id
#XmlElement
Integer linguaIdlingua;
/**
*/
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "version", nullable = false)
#Basic(fetch = FetchType.EAGER)
#XmlElement
Calendar version;
...
I'm getting....can you help me?
ERROR: HSEARCH000058: HSEARCH000116: Unexpected error during MassIndexer operation
java.lang.ClassCastException: it.domain.InterventoPK cannot be cast to java.lang.Integer
at org.hibernate.type.descriptor.java.IntegerTypeDescriptor.unwrap(IntegerTypeDescriptor.java:36)
at org.hibernate.type.descriptor.sql.IntegerTypeDescriptor$1.doBind(IntegerTypeDescriptor.java:57)
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:92)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:305)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:300)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1891)
at org.hibernate.loader.Loader.bindParameterValues(Loader.java:1862)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1737)
at org.hibernate.loader.Loader.doQuery(Loader.java:828)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:289)
at org.hibernate.loader.Loader.doList(Loader.java:2447)
at org.hibernate.loader.Loader.doList(Loader.java:2433)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2263)
at org.hibernate.loader.Loader.list(Loader.java:2258)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:122)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1535)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:374)
at org.hibernate.search.batchindexing.impl.IdentifierConsumerEntityProducer.loadList(IdentifierConsumerEntityProducer.java:150)
at org.hibernate.search.batchindexing.impl.IdentifierConsumerEntityProducer.loadAllFromQueue(IdentifierConsumerEntityProducer.java:117)
at org.hibernate.search.batchindexing.impl.IdentifierConsumerEntityProducer.run(IdentifierConsumerEntityProducer.java:94)
at org.hibernate.search.batchindexing.impl.OptionallyWrapInJTATransaction.run(OptionallyWrapInJTATransaction.java:84)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Hibernate Search does not handle composite id classes used with #IdClass. A workaround would be to use #EmbeddedId and place idintervento and linguaIdlingua into InterventoPK.
Seems also that you asked the same question on the Hibernate Search forum - https://forum.hibernate.org/viewtopic.php?f=9&t=1024512
You can convert your custom object / composite key to Lucene Understandable format by using bridges. For example for a class
#Entity
#Indexed
public class Person {
#EmbeddedId #DocumentId Embedded id
#FieldBridge(impl=PersonPkBridge.class)
private PersonPK id;
...
}
You can write the bridge as like this. These codes are from the book 'Hibernate Search In Action'. I found it very helpful.
Does your class declared as composite key (it.domain.InterventoPK.class, as declared via #IdClass class-level annotation) only contain two integer fields? Since you've also annotated two such Integer fields with #Id on your Intervento class, the composite key class must only contain those fields and they must have the same name. Also that composite PK class needs to be Serializable. From the docs:
"map multiple properties as #Id properties and declare an external class to be the identifier type. This class, which needs to be Serializable, is declared on the entity via the #IdClass annotation. The identifier type must contain the same properties as the identifier properties of the entity: each property name must be the same, its type must be the same as well if the entity property is of a basic type, its type must be the type of the primary key of the associated entity if the entity property is an association (either a #OneToOne or a #ManyToOne)."
http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/
(search "Composite identifier" in page)
I had already replied on your question on the Hibernate forums, but to complete my suggestion:
An alternative to changing your mapping is that you add add a #DocumentId on a new getter, and return any object - maybe even a string - which is a unique composite of the two ids components.
(This requires defining mapping on getters and setters however)
When using JPA you can avoid specifying the #DocumentId but you don't have to, you can still use the annotation to override the definition of identity which you want to apply on the index mapping.
I have a below mapping
#Entity
#Table(name = "auctions")
public class Auction{
.
.
#OneToMany(cascade = CascadeType.ALL, mappedBy = "auction")
private List<AuctionParamValue> auctionParamValueList;
.
.
}
#Entity
#Table(name = "auction_param_values")
public class AuctionParamValue {
#EmbeddedId
protected AuctionParamValuePK auctionParamValuePK;
#JoinColumn(name = "auction_param_id", referencedColumnName = "auction_param_id",updatable=false,insertable=false)
#ManyToOne #MapsId("auctionParamId")
private AuctionParam auctionParam;
#JoinColumn(name = "auction_id", referencedColumnName = "auction_id",updatable=false,insertable=false)
#ManyToOne #MapsId("auctionId")
private Auction auction;
}
#Embeddable
public class AuctionParamValuePK {
#Id
#Basic(optional = false)
#Column(name = "auction_id")
#Nullable
private Long auctionId = null;
#Id
#Basic(optional = false)
#Column(name = "auction_param_id")
#Nullable
private Long auctionParamId = null;
}
#Entity
#Table(name = "auction_params")
public class AuctionParam {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "auctionParam")
private List<AuctionTypeParam> auctionTypeParamList;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "auctionParam")
private List<AuctionParamValue> auctionParamValueList;
}
}
When I try to persist auction (I am manually setting the auctionParamId and expecting the auctionId to be automaticlly set (may be the last inserted id) )
but I am getting below error, I am not sure why the auctionId in the query is going as 0 instead of latest id in the auction.(I am using eclipselink jpa provider)
Internal Exception: com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`portaldemo`.`auction_param_values`, CONSTRAINT `auction_param_values_auction_id_fk` FOREIGN KEY (`auction_id`) REFERENCES `auctions` (`auction_id`))
Error Code: 1452
Call: INSERT INTO auction_param_values (auction_param_val, create_ts, last_updt_ts, auction_param_id, auction_id) VALUES (?, ?, ?, ?, ?)
bind => [2011-02-12 04:00:00, 2011-01-27 12:02:00.28, 2011-01-27 12:17:43.25, 2, 0]
Query: InsertObjectQuery(com.eaportal.domain.AuctionParamValue[auctionParamValuePK=com.eaportal.domain.AuctionParamValuePK[auctionId=0, auctionParamId=2]])
Here the [auctionId=0 is always comming as 0 and not the last inserted id :(
What is theproblem with this mapping ?
An #GeneratedValue will only set the value of the attribute it is annotated on, if you have other attributes in other classes that reference the id you are responsible for setting these.
i.e. you would need to first persist and flush the Auction, and then create the AuctionParamValue using its generate Id.
Or, if you used TABLE or SEQUENCE id generation then you would just need to call persist, and not the flush. In general I would never recommend IDENTITY sequencing as its values cannot be preallocated.
But really you should not have the duplicate fields as all. Remove the #EmbeddedId auctionParamValuePK entirely and just add #Id to the two #ManyToOnes, and use an #IdClass instead. This will make things much simplier and will just work, even with IDENTITY id generation.
You could also instead remove the insertable/updateable=false on the two #ManyToOne mappings and instead put them on the #EmbeddedId attributes, this will have the foreign key written from the relationships, but your object will still be corrupt in memory.
See,
http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Primary_Keys_through_OneToOne_and_ManyToOne_Relationships
You could try two things:
make the two ids nullable: Use wrapper Types instead of primitives (Integer, Long), and set it to null before saving
leave the combinded Primary ID field (auctionParamValuePK) empty (null) when you save it.
I don't know if this fix the problem, but I am sure that you need to do at least one of them to get it working.