PostgreSQL JPA cascade partially working - database

Again we probably have a very simple problem;
our database look like:
CREATE TABLE Question (
idQuestion SERIAL,
questionContent VARCHAR,
CONSTRAINT Question_idQuestion_PK PRIMARY KEY (idQuestion),
);
CREATE TABLE Answer (
idAnswer SERIAL,
answerContent VARCHAR,
idQuestion INTEGER,
CONSTRAINT Answer_idAnswer_PK PRIMARY KEY (idAnswer),
CONSTRAINT Answer_idQuestion_FK FOREIGN KEY (idQuestion) REFERENCES Question(idQuestion),
);
So a Question have many Answers.
Following in entity generated by Netbeans 7.1.2 we have field:
#OneToMany(mappedBy = "idquestion", orphanRemoval=true, cascade= CascadeType.ALL, fetch= FetchType.EAGER)
private Collection<Answer> answerCollection;
As you can see I've already added all possible orphan removal and cascade instructions for cascade removal of collection. And it's working fine but for one moment:
You can delete a Question and connected Answers only if they were created in previous 'instance' of our Application. If I first create a new Question and even one Answer and then go straight and delete it we got an error like:
root cause
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: update or delete on table "question" violates foreign key constraint "answer_idquestion_fk" on table "answer"
Detail: Key (idquestion)=(30) is still referenced from table "answer".
Error Code: 0
Call: DELETE FROM question WHERE ((idquestion = ?) AND (version = ?))
bind => [2 parameters bound]
Query: DeleteObjectQuery(com.accenture.androidwebapp.entities.Question[ idquestion=30 ])
root cause
org.postgresql.util.PSQLException: ERROR: update or delete on table "question" violates foreign key constraint "answer_idquestion_fk" on table "answer"
Detail: Key (idquestion)=(30) is still referenced from table "answer".
If I restart (rebuild, redeploy) the application it's working though.. why? Thanks!

Try adding the EclipseLink #PrivateOwned extension annotation to your collection mapping.
As for the issue with deletion not working until you restart the app, two things come to mind:
You might be using very long EntityManager sessions where everything stays attached to the EnitityManager. If that's the case, it's the change of EntityManager session forced by a restart that's helping. Consider using shorter EntityManager sessions by calling EntityManager.close() when you're done with a session. Work with detached entities and EntityManager.merge() state back in when you want to modify it.
The second level cache, if any, will be cleared by a redeploy. Try disabling the second level cache and see if that helps.

Related

How to figure out what exact entity resulted in DbContext.SaveChanges FK conflict failure

With Entity Framework Core (in case it matters, I'm using version 2.2), I update a number of entities in the DB context and call SaveChanges. In case saving fails because of the foreign key issue, I can't figure out what exact entities have foreign key issues. Is it possible to figure this out?
When Foreign Key conflict happens, SQL Server returns an error with code 547 and text The UPDATE statement conflicted with the FOREIGN KEY constraint "<Constraint>". The conflict occurred in database "<Database name>", table "<Table name>", column '<Column name>' without reference to exact invalid rows.
I have looked at DbUpdateException properties, but no luck:
var dbUpdateEx = ex as DbUpdateException;
var erroredEntries = dbUpdateEx.Entries;
// The documentation says that Entries property "Gets the entries that were involved in the error",
// but in my case it's always empty.
Also, I have tried validating entities manually before save, but such validation does not find FK conflicts. Code sample:
var valProvider = new ValidationDbContextServiceProvider(dbContext);
var valContext = new ValidationContext(entity, valProvider, null);
var entityErrors = new List<ValidationResult>();
var result = Validator.TryValidateObject(entity, valContext, entityErrors, true);
When I save more than 100 records and the save fails because of FK conflict in a single entity, it's quite frustrating to look for this single invalid record by hand.

web2py: FOREIGN KEY constraint failed when it shouldn't

I have this table:
db.define_table('block',
Field('ore_id', 'reference ore'),
Field('location', type='integer', required=True, notnull = True),
Field('x', type='integer'),
Field('y', type='integer'),
Field('block_mass_tn', type='double')
)
and this:
db.define_table('block_processing_line_1',
Field('block_location', 'reference block'),
Field('processing_time_d', type='double'),
Field('concentrate_tn', type='double'),
Field('concentrate_quality', type='double')
)
In the table block I have 100 entries, id and location running from 1-100. When I add a new record to the latter table with block_location being 1, it accepts it, but when I try to add 2 or 3 or so on, it won't accept it and it says "FOREIGN KEY constraint failed". I have other tables, which have that identical field: Field('block_location', 'reference block'), but they don't have any problem with values above 1. What is wrong here?
One other thing that comes in mind is that I had the same problem before with that table and I realized I had made a typo: Field('block_location', 'reference ore'), so I referenced a wrong table and that table ore only had one entry (thus accepting only 1 and nothing else). But now even though I fixed it, the problem persists. Could there be some traces of that former line somewhere in the DAL? I truncated both tables (block and block_processing_line_1after fixing.
#Anthony:
Have you compiled the app or turned off migrations? If neither, maybe
try dropping the block_processing_line_1 table.
This solved it! I dropped the table and saved, "undropped" the table and saved, and after that it worked as it should. So this line:
db.block_processing_line_1.drop()

Cayenne, Postgres: primary key generation

I'm using Cayenne 3.2M1 and Postgres 9.0.1 to create a database. Right now I'm having problems with the primary key generation of Cayenne since I have tables with more than one primary key and as far as I've read Cayenne cant generate more that one primary key per table. So I want the Postgres to do that work.
I have this table:
CREATE TABLE telefonocliente
(
cod_cliente integer NOT NULL DEFAULT currval('cliente_serial'::regclass),
cod_telefono integer NOT NULL DEFAULT nextval('telefonocliente_serial'::regclass),
fijo integer,
CONSTRAINT telefonocliente_pkey PRIMARY KEY (cod_cliente, cod_telefono)
)
WITH (
OIDS=FALSE
);
TelefonoCliente telefono = context.newObject(TelefonoCliente.class);
telefono.setFijo(4999000);
context.commitChanges();
and this is the error I get:
INFO: --- transaction started.
19/11/2013 22:46:17 org.apache.cayenne.access.dbsync.CreateIfNoSchemaStrategy processSchemaUpdate
INFO: Full or partial schema detected, skipping tables creation
19/11/2013 22:46:17 org.apache.cayenne.log.CommonsJdbcEventLogger logQuery
INFO: SELECT nextval('pk_telefonocliente')
Exception in thread "main" org.apache.cayenne.CayenneRuntimeException: [v.3.2M1 Jul 07 2013 16:23:58] Commit Exception
at org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:759)
at org.apache.cayenne.access.DataContext.commitChanges(DataContext.java:676)
at org.example.cayenne.Main.main(Main.java:45)
Caused by: org.postgresql.util.PSQLException: ERROR: no existe la relaci?n ≪pk_telefonocliente≫
Position: 16
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:500)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:374)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:254)
at org.apache.cayenne.dba.postgres.PostgresPkGenerator.longPkFromDatabase(PostgresPkGenerator.java:79)
at org.apache.cayenne.dba.JdbcPkGenerator.generatePk(JdbcPkGenerator.java:272)
at org.apache.cayenne.access.DataDomainInsertBucket.createPermIds(DataDomainInsertBucket.java:171)
at org.apache.cayenne.access.DataDomainInsertBucket.appendQueriesInternal(DataDomainInsertBucket.java:76)
at org.apache.cayenne.access.DataDomainSyncBucket.appendQueries(DataDomainSyncBucket.java:78)
at org.apache.cayenne.access.DataDomainFlushAction.preprocess(DataDomainFlushAction.java:188)
at org.apache.cayenne.access.DataDomainFlushAction.flush(DataDomainFlushAction.java:144)
at org.apache.cayenne.access.DataDomain.onSyncFlush(DataDomain.java:685)
at org.apache.cayenne.access.DataDomain$2.transform(DataDomain.java:651)
at org.apache.cayenne.access.DataDomain.runInTransaction(DataDomain.java:712)
at org.apache.cayenne.access.DataDomain.onSyncNoFilters(DataDomain.java:648)
at org.apache.cayenne.access.DataDomain$DataDomainSyncFilterChain.onSync(DataDomain.java:852)
at org.apache.cayenne.access.DataDomain.onSync(DataDomain.java:629)
at org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:727)
... 2 more
I've been trying the suggestions on Cayenne tutorial "generated columns", "primary key support" but I seems to always get some error.
INFO: SELECT nextval('pk_telefonocliente')
Exception in thread "main" org.apache.cayenne.CayenneRuntimeException: [v.3.2M1 Jul 07 2013 16:23:58] Primary Key autogeneration only works for a single attribute.
I want to know how to solve this.
Thanks in advance
From your description in comments, out of 2 columns comprising the PK of 'telefonocliente', only one is truly independent - 'cod_telefono'. This will be what Cayenne will generate. In case of PosgreSQL, you will need the following sequence in DB for this to happen:
CREATE SEQUENCE pk_telefonocliente INCREMENT 20 START 200;
Now, where does the second PK 'cod_cliente' come from? Since it is also FK to another table, it means it is a "dependent" PK, and must come from a relationship. So first you need to map a many-to-one relationship between 'telefonocliente' and 'cliente'. Check "To Dep Pk" checkbox on the 'telefonocliente' side. Generate a matching ObjRelationship for your Java objects. Now you can use it in your code:
Cliente c = .. // get a hold of this object somehow
TelefonoCliente telefono = context.newObject(TelefonoCliente.class);
telefono.setFijo(4999000);
telefono.setCliente(c); // this line is what will populate 'cod_cliente' PK/FK
That should be it.
The primary key is allowed just to be one per a table! In your case you create a primary key on two columns, that is right, it is defined in an SQL standard and Postgres supports it well.
However there is a not in Cayenne documentation:
Cayenne only supports automatic PK generation for a single column per table.
see http://cayenne.apache.org/docs/3.0/primary-key-generation.html at the bottom of the page.
Probably they can fix it in a newer version or you can put a request to the Cayenne community.

Play Framework using Oracle Database - ORA-00942: table or view does not exist

I can't solve my problem with my local Oracle database.
I'm tryong to connect to my local Oracle database (Oracle Database 11g Express Edition)
Later on I will use JNDI to another Oracle Database, but I think this should still work.
Driver: ojdbc6.jar in /lib
db.default.driver=oracle.jdbc.driver.OracleDriver
db.default.url="jdbc:oracle:thin:#localhost:1521:xe"
db.default.user="user"
db.default.pass="pass"
So I know I do connect to the database, but the error is that it says that the table does not exist. I'm not even creating or querying to a table (no model exists - but I've tried with having a model too, same error). Something seems to be wrong in the beginning and I don't know how to Debug this.
Error:
**java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist**
oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:457)
oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:400)
oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:926)
oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:476)
oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:200)
oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:543)
oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:197)
oracle.jdbc.driver.T4CStatement.executeForDescribe(T4CStatement.java:1213)
oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1492)
oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1710)
oracle.jdbc.driver.OracleStatement.executeQuery(OracleStatement.java:2006)
oracle.jdbc.driver.OracleStatementWrapper.executeQuery(OracleStatementWrapper.java:1709)
com.jolbox.bonecp.StatementHandle.executeQuery(StatementHandle.java:503)
play.api.db.evolutions.Evolutions$.executeQuery(Evolutions.scala:118)
play.api.db.evolutions.Evolutions$.databaseEvolutions(Evolutions.scala:334)
play.api.db.evolutions.Evolutions$.evolutionScript(Evolutions.scala:306)
play.api.db.evolutions.EvolutionsPlugin$$anonfun$onStart$1$$anonfun$apply$1.apply$mcV$sp(Evolutions.scala:435)
play.api.db.evolutions.EvolutionsPlugin.withLock(Evolutions.scala:478)
play.api.db.evolutions.EvolutionsPlugin$$anonfun$onStart$1.apply(Evolutions.scala:434)
play.api.db.evolutions.EvolutionsPlugin$$anonfun$onStart$1.apply(Evolutions.scala:432)
scala.collection.immutable.List.foreach(List.scala:309)
play.api.db.evolutions.EvolutionsPlugin.onStart(Evolutions.scala:432)
play.api.Play$$anonfun$start$1$$anonfun$apply$mcV$sp$1.apply(Play.scala:63)
play.api.Play$$anonfun$start$1$$anonfun$apply$mcV$sp$1.apply(Play.scala:63)
scala.collection.immutable.List.foreach(List.scala:309)
play.api.Play$$anonfun$start$1.apply$mcV$sp(Play.scala:63)
play.api.Play$$anonfun$start$1.apply(Play.scala:63)
play.api.Play$$anonfun$start$1.apply(Play.scala:63)
When reading about it I've only found that I might not have permission to some table, but the thing is that I use the same login in Oracle SQL Developer and it works.
As nico_ekito wrote, you need to create this table manually.
This one works for me:
CREATE TABLE play_evolutions
(
id Number(10,0) Not Null Enable,
hash VARCHAR2(255 Byte),
applied_at Timestamp Not Null,
apply_script clob,
revert_script clob,
state Varchar2(255),
last_problem clob,
CONSTRAINT play_evolutions_pk PRIMARY KEY (id)
);
Try to manually create a play_evolutions table with the following columns (by adapting the types to the ones used by Oracle):
id int not null primary key, hash varchar(255) not null,
applied_at timestamp not null,
apply_script text,
revert_script text,
state varchar(255),
last_problem text
In conf/application.conf
Un-comment the following line:
evolutionplugin=disabled
This is if you don't need Evolutions (to track schema changes).

Creating two new database tables for Magento

I'm trying to add two tables to magento but it still dosen't work! I don't get the tables in MySQL.
There's no error message, just nothing happens.
I can't find where the mistake is;
I already checked all my pages.
This is my XML code in config.xml:
<models>
<interactivebanner>
<class>Kiwi_InteractiveBanner_Model</class>
<resourceModel>InteractiveBanner_resource</resourceModel>
</interactivebanner>
<interactivebanner_resource>
<class>Kiwi_InteractiveBanner_Model_Resource</class>
<entities>
<interactivebanner>
<table>interactivebanner</table>
</interactivebanner>
<interactivebanner2>
<table>interactivebanner_prod</table>
</interactivebanner2>
</entities>
</interactivebanner_resource>
</models>
and this is the setup page :
<?php
$installer = $this;
$installer->startSetup();
$installer->run("
DROP TABLE IF EXISTS `{$this->getTable('interactivebanner/interactivebanner')}`;
create table `{$this->getTable('interactivebanner/interactivebanner')}`
(
ENTITY_ID int not null,
NAME varchar(100),
LINK varchar(100),
STATUS int,
primary key (ENTITY_ID)
);
DROP TABLE IF EXISTS `{$this->getTable('interactivebanner/interactivebanner_prod')}`;
create table `{$this->getTable('interactivebanner/interactivebanner_prod')}`
(
PROD_ID int not null,
ENTITY_ID int,
POSI_V float,
POSI_H float,
primary key (PROD_ID)
);
alter table banner_pro add constraint FK_RELATION_1 foreign key (ENTITY_ID)
references banner (ENTITY_ID) on delete restrict on update restrict;
");
$installer->endSetup();
Is this existing module you want to upgrade?
If so, you will have to bump the module version before your upgrade script runs. If it's a separate module you have to make the mysql4-setup-<version>.php with a version so high or above that will create the tables. Also you will require to have module declaration in your app/etc/Myself_Interactivebanner.xml so that Magento knew about the module existence.
To get more certain answer provide more details about the environment you have.
If I had to guess, your install script is not running. This can happen for multiple reasons. I would look at this post that helped me get my install script running:
My Magento Extension Install Script Will Not Run
i found a mistake on my config.xml !
an uppercase missing :)
sorry.

Resources