I am working with Spring 3 and Mybatis 3.
Everything is working ok just when i want to make a cascade delete.
Ive got 2 tables with a middle M-M relationship table. Something like Table1 ---> MiddleTable ---> Table2
I want to make a deletion from the midle table and after that delete de data related in the Table2.
In using a Transactional method
#Transactional
public void relacionaReservaLibreBonoLibre(ParametrosRelacionReservaBono params) throws Exception{
ReservaBean r=rm.buscarReservaPorPK(params.getReserva());
for(BonoJson b:params.getListaBonosAdd()){
HotelBean h=hm.buscaHotelPorCodHotel(b.getHotel());
EstacionBean e=em.buscaEstacionPorEstacionYHotel(b.getEstacion(),h.getCnHotel());
DocumentoBean db=new DocumentoBean();
db.setCnEstacion(e.getCnEstacion());
db.setCnHotel(h.getCnHotel());
db.setCnTipDoc(r.getCnTipoDoc());
db.setFlLibre(true);
db.setTeDoc(b.getCodBono());
Integer docId=dm.insertaDocumento(db);
DocumentoReservaBean drb=new DocumentoReservaBean();
drb.setCnDoc(docId);
drb.setCnReserva(r.getCnReserva());
drm.insertaDocumentoReserva(drb);
}
for(BonoJson b:params.getListaBonosQuit()){
HotelBean h=hm.buscaHotelPorCodHotel(b.getHotel());
EstacionBean e=em.buscaEstacionPorEstacionYHotel(b.getEstacion(),h.getCnHotel());
ReservaDocumentoReservaBean filtro=new ReservaDocumentoReservaBean();
filtro.setTeDoc(b.getCodBono());
filtro.setCnReserva(r.getCnReserva());
filtro.setFlLibre(true);
List<ReservaDocumentoReservaBean> resPrev=rdm.getReservaDocumentos(filtro);
for(ReservaDocumentoReservaBean resPart:resPrev){
DocumentoReservaBean drb=new DocumentoReservaBean();
drb.setCnDocReserva(resPart.getCnDocReserva());
drm.eliminaDocumentoReservaPorPK(drb);
DocumentoBean db=new DocumentoBean();
db.setCnDoc(resPart.getCnDoc());
dm.eliminaDocumentoPorPK(db);
}
}
}
It works great just when is executes de
dm.eliminaDocumentoPorPK(db);
It launches the Constraint violation Table2 to Middle table, that its suposed to be deleted in
drm.eliminaDocumentoReservaPorPK(drb);
¿Any hint?
Thanks in advance.
There are several options:
Delete from Table2 and then delete from MiddleTable
If this is acceptable (that is MiddleTable entity owns Table2 entity) then change foreign key in database so that rows in Table2 were deleted by cascade when row in MiddleTable is deleted. Just add ON CASCADE DELETE to foreign key from Table2 to MiddleTable definition.
Make foreign key constrain deferred if your database supports this.
Related
currently i am facing an oracle constraints issue.
After submiting an insert my foreign key constraint(s) won't fire. What it should do is giving two tables the same ID, but unfortunately only the one table with the primary Key is giving an ID. The column with the foreign key in the second table remains null.
For Instance: Insert into table t1 (t1_id,name, dpt) values (value1 (trigger with autoincrement for id), value2, value3); The same procedure is behind table 2, table 3 ... All constraints are written correctly
Table 1 (Emp)
ID Name Department
1 Joe HR
Table 2 (Projects)
ID Project EmpID
1 new (null) -> must be 1
Thank you in advanced.
Constraint: ALTER TABLE "PROJECTS" ADD CONSTRAINT "EMP_FK" FOREIGN KEY ("EMP_ID")
REFERENCES "EMP" ("EMP_ID") ON DELETE CASCADE ENABLE
Trigger: create or replace TRIGGER Projects_TRG BEFORE
INSERT ON Projects FOR EACH ROW BEGIN :NEW.Project_ID := Projects_SEQ.NEXTVAL;
END;
How do i manage to populate the parent id from the parent table into the child table?
Please note that I used different names in my application.
It appears that you've misunderstood the purpose of a foreign key constraint. A foreign key constraint does NOT automatically propagate constraint values from the parent table to the child table. The purpose of the constraint is to ensure that the values of the key column in the child table, when populated, have matching values in the key column of the parent table. Your application is responsible for ensuring that the key column on the child table is populated with the appropriate value. The constraint doesn't do that for you. It's also perfectly legitimate to have a NULL in the key column of the child table, assuming the the column on the child table doesn't have a NOT NULL constraint on it.
I have a Spring server with use JPA and H2 to store data.
A database table is created using this class:
#Entity
public class parametros {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
long idproject;
#ElementCollection(fetch=FetchType.EAGER)
List<String> answers = new ArrayList<String>();
public parametros(){
}
.../* gets and sets */
}
So, JPA and H2 creates automatically a database within a Table="parametros" and another Table="parametros_answers" like this:
Table = "parametros"
ID | IDPROJECT
1 | 3
2 | 6
Table="parametros_answers"
PARAMETROS_ID | ANSWERS
1 | Masculine
1 | Female
1 | Other
2 | Cocacola
2 | Pepsi
So, the system is creating a foreign key in the Table = "parametros_answer" .
Until this point all is OK. The problem comes when I try to EDIT a column value from Table = "parametros". The only way I know to change a column value is using UPDATE SET statement. So when I try to do:
UPDATE PARAMETROS SET IDPROJECT=10 WHERE IDPROJECT=3 this Error Appears:
Error "DELETE FROM PUBLIC.PARAMETROS WHERE ID=? AND IDPROJECT=? , cause: "org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: ""FK_NFSJ58KBBAYJ84HFJLOCV9JEQ: PUBLIC.PARAMETROS_ANSWERS FOREIGN KEY(PARAMETROS_ID) REFERENCES PUBLIC.PARAMETROS(ID) (1)""; SQL statement:
DELETE FROM PUBLIC.PARAMETROS WHERE ID=? AND EXTRA_CONF=? AND IDPROJECT=? AND MULTI_MAXIMUM=? AND MULTI_MINIMUM=? AND NOTE=? AND PERGUNTA=? AND TITLE=? AND TYPE=? [23503-187]"; SQL statement:
The exception says what is the problem: you are violating the referential integrity.
All 'parametros_answers' rows have to point to a 'parametros'. You cannot delete or update 'parametros' without deleting or updating the connections first from 'parametros_answers' in the same transaction.
Or remove the foreign key constraint.
Or use entitymanager which automatically deletes/updates these rows if you mark the collection accordingly: #Cascade(value={CascadeType.ALL})
So, I don't know if this solution is the best but is the only one that works for me. Maybe the #highstakes solution will work when the DataBase is empty but in my case is not.
Steps i followed:
1 - Copy the parametros_answers table (the one which has the foreig key) like this:
CREATE TABLE PARAMETROS_ANSWERS_AUX AS SELECT * FROM PARAMETROS_ANSWERS
2 - Delete the parametros_answers table:
DROP TABLE PARAMETROS_ANSWER
2 - After that, I can do the changes I need on parametros table:
UPDATE PARAMETROS SET IDPROJECT=10 WHERE IDPROJECT=3
3 - I create again the parametros_answers by copying that from the parametros_answers_aux table:
CREATE TABLE PARAMETROS_ANSWERS AS SELECT * FROM PARAMETROS_ANSWERS_AUX
4 - Finally I can delete the auxiliar table parametros_answers_aux:
DROP TABLE PARAMETROS_ANSWERS_AUX
I have the following tables:
create table emp_test_lucian as select employee_id,last_name,first_name,department_id from employees;
ALTER TABLE emp_test_lucian
ADD PRIMARY KEY (employee_id);
create table dept_test_lucian as select department_id,department_name from departments_copy;
ALTER TABLE dept_test_lucian
ADD PRIMARY KEY (department_id);
On this tables I want to perform different operations for example: If a department gets deleted (from dept_test_lucian) I will delete all the rows in emp_test_lucian that have that department id with a trigger. This works fine when no fk between the 2 is declared with the following code :
CREATE OR REPLACE TRIGGER triger5
BEFORE UPDATE or DELETE on dept_test_lucian
FOR EACH ROW
BEGIN
IF DELETING then
delete
from emp_test_lucian
where department_id = :OLD.department_id;
else if UPDATING('department_id') then
UPDATE emp_test_lucian
set department_id = :NEW.department_id
where department_id = :OLD.department_id;
END IF;
END IF;
END;
/
What can I add to the code above to work even if I have a fk between the 2 tables like so:
ALTER TABLE emp_test_lucian
ADD CONSTRAINT fk_dep_id FOREIGN KEY(department_id) REFERENCES dept_test_lucian(department_id);
the current code returns :
Error report:
ORA-00001: unique constraint (C##LABORATOR.SYS_C009994) violated
ORA-06512: at line 2
00001. 00000 - "unique constraint (%s.%s) violated"
*Cause: An UPDATE or INSERT statement attempted to insert a duplicate key.
For Trusted Oracle configured in DBMS MAC mode, you may see
this message if a duplicate entry exists at a different level.
*Action: Either remove the unique restriction or do not insert the key.
You need to make clear what table is the 'parent' and what table is the 'child'.
In your example:
- Parent: dept_test_lucian
- Child: emp_test_lucian
Lets call 'dept_test_lucian': TableA
Lets call 'emp_test_lucian': TableB
I come to this conclusion since there is a CONSTRAINT on TableB.department_id" that can only have a value that exists
in "TableA.department_id"
The error message tells you that there is a 'primary key being vialated'.
Primary keys on you tables are:
- "TableA.employee_id"
- "TableB.department_id"
Apparently you are trying to insert a value in one of these columns where that value already exists in.
If '1' is already existing in "TableA.employee_id" you would get such an error.
What I also see in your trigger is:
You have a BEFORE UPDATE Trigger.
So the Trigger looks if there is an UPDATE comming on "TableA" (Parent).
Then you try to UPDATE "TableB" (child) first.
This could be tricky, since "TableB.department_id" can only have values that exist in "TableA.department_id".
If the new UPDATE value doesn't exist in "TableA.department_id", you can not UPDATE that value in "TableB.department_id"
I am Using Transaction Scope for Performing the Insert In Multiple Tables using Try and Catch. But when i am Getting the Error Within Transaction Scope it's not allowing me to Save the Data in catch also.
My Code
using (var transaction = new TransactionScope())
{
try
{
//Insert in Table1
//Insert in Table2
//Insert in Table3
transaction.Complete();
transaction.Dispose();
}
catch(Exception ex)
{
transaction.Dispose();
//Insert in ErrorHandlerTable (Independent Table)
}
}
Now The Problem is whenever i am getting the error in try block for foreign key constraints i am unable to insert into ErrorHandlerTable (Independent Table). Always Getting Following Exception:
{"The INSERT statement conflicted with the FOREIGN KEY constraint \"FK_Table1_PkId\". The conflict occurred in database \"MyTransactionDatabase\", table \"dbo.Table2\", column 'PkId'.\r\nThe statement has been terminated."}
Can anyone help in this?
I think this will help you to revert the operations in the tables, please try using below stuff
using (var transaction = new TransactionScope())
{
try
{
//Insert in Table1
//Insert in Table2
//Insert in Table3
transaction.Complete();
transaction.Dispose();
}
catch(Exception ex)
{
transaction.Dispose();
//what i have changed
context.Table1 Table1Object = new YoSafari.Migration.EntityFramework.Table1(); //Create New Object of the table in which u want to insert i.e. Table1 or Table2 etc..
using (var context = new ContextClass())
{
context.Entry(Table1Object).State = EntityState.Unchanged;
//Insert in ErrorHandlerTable (Independent Table i.e. Table1 or Table2 etc..)
context.SaveChanges();
}
}
}
It will create new object of the tables that will Unchanged the operations and allow you to insert the record in to your ErrorHandlerTable
Please let me know if you are still facing any issue with this.
As answered here INSERT statement conflicted with the FOREIGN KEY constraint :-
In your table ysmgr.Table2, it has a foreign key reference to
another table. The way a FK works is it cannot have a value in that
column that is not also in the primary key column of the referenced
table.
If you have SQL Server Management Studio, open it up and sp_help
'ysmgr.Table2'. See which column that FK is on, and which
column of which table it references. You're inserting some bad data.
So the steps are :-
1.run sp_helpconstraint
2.pay ATTENTION to the constraint_keys column returned for the foreign key
The problem is that, even if your code has disposed the TransactionScope, when it inserts the data in the ErrorHandlerTable tha happens still inside the TransactionScope. So, something is going wrong, and you get a misleading error.
To avoid this, change the code so that the insertion in the ErrorHandlerTable is done outside of the original transaction scope. To do so, you can nest a new using block to provide a new, independent TransactionScope like this:
using(var ts = new TrasanctionScope(TransactionScopeOption.RequiresNew)
or this
using(var ts = new TrasanctionScope(TransactionScopeOption.Suppress)
The first option simply creates a new transaction, indepenend of the original one. But, if your insert is an atomic operation, as it seems, you can also use the second option, which creates a new independent transactionless scope.
In this way you can be sure that your insertion in the ErrorHandlerTable happens without any interference with the original transaction scope.
Please, see this docs:
TransactionScope Constructor (TransactionScopeOption)
TransactionScopeOption Enumeration
I have a table STUDENT with columns st_id,name,age,dept_name. Now I want to create a new table STUDENT_DESC with columns st_id,dept_name,st_desc. So I need to copy all the values of st_id and dept_name to the newly created table STUDENT_DESC. I need to ensure relationship while copying st_id and dept_name , the dept_name should be corresponding to st_id.So how can I do it in PL/SQL?
insert into STUDENT_DESC (select st_id, dept_name, null from student);
this will simply copy all the records. The third column st_desc is left empty (null)
To ensure referential integrity you would add a primary key and a referential integrity constraint to the STUDENT_DESC table
However, note that in many cases it could be "wrong" to introduce a second table containing student data like that. It could be "better" to add st_desc to the STUDENT table.
I'm not sure I understand your data model, but at face value you can create your table simply:
CREATE TABLE student_desc AS SELECT st_id, dept_name FROM student;
ALTER TABLE student_desc ADD (st_desc VARCHAR2(..));
Fill in the .. with the desired max size for st_desc.