On delete cascade for self-referencing table
Assuming you're keeping your FOREIGN KEY
constraint in place, you cannot fix the issue in a FOR DELETE
trigger. FOR
triggers (also known as AFTER
triggers) fire after the activity has taken place. And a foreign key will prevent a row from being deleted if it has references. Foreign key checks occur before deletion.
What you need is an INSTEAD OF
trigger. You also need to bear in mind that your current trigger only tried to deal with one "level" of referencing. (So, if row 3 references row 2 and row 2 references row 1, and you delete row 1, your trigger only tried to remove row 2)
So, something like:
CREATE TRIGGER [dbo].[T_comment_Trigger]
ON [dbo].[Comments]
INSTEAD OF DELETE
AS
;WITH IDs as (
select id from deleted
union all
select c.id
from Comments c
inner join
IDs i
on
c.ParentID = i.id
)
DELETE FROM Comments
WHERE id in (select id from IDs);
If there are other (non-self-referencing) cascading foreign key constraints, they all have to be replaced by actions in this trigger. In such a case, I'd recommend introducing a table variable to hold the list of all IDs that will eventually be deleted from the Comments
table:
CREATE TRIGGER [dbo].[T_comment_Trigger]
ON [dbo].[Comments]
INSTEAD OF DELETE
AS
declare @deletions table (ID varchar(7) not null);
;WITH IDs as (
select id from deleted
union all
select c.id
from Comments c
inner join
IDs i
on
c.ParentID = i.id
)
insert into @deletions(ID)
select ID from IDs
-- Delete from FK referenced table
DELETE FROM OtherTable
WHERE CommentID in (select ID from @deletions)
--This delete comes last
DELETE FROM Comments
WHERE id in (select ID from @deletions);
MySQL cascade delete on self-referencing parent-child table?
When you enter any value into the parent_id column of a new row, the foreign key requires that there is a row where id has that value, because that's how foreign keys work.
If you want to use a foreign key with your self-referencing relationship, you should use NULL instead of 0 for the parent_id
of a row that has no parent to reference. Foreign keys ignore NULL.
How to delete on cascade a self reference relationship?
You are trying to do another DELETE in a DELETE trigger which is disallowed as this can go into an infinite loop.
You might want to change your use a INSTEAD OF DELETE
trigger (see this link) and change your trigger body code to something like below
UPDATED: To address the error that @TT pointed out.
CREATE TABLE #CascadeDeleteRows (IDTableA int, IDTableARoot int)
INSERT
INTO #CascadeDeleteRows
SELECT b.IDTable
, b.IDTableARoot
FROM TableA
WHERE b.IDTableA IN (SELECT deleted.IDTableARoot from deleted)
DELETE
FROM TableA
WHERE IDTableA IN (SELECT #CascadeDeleteRows.IDTableA FROM #CascadeDeleteRows)
DROP TABLE #CascadeDeleteRows
Hope this helps
On DELETE CASCADE fails in self referencing MySQL table having depth more than 15 levels
This is documented behavior:
If ON UPDATE CASCADE or ON UPDATE SET NULL recurses to update the same
table it has previously updated during the cascade, it acts like
RESTRICT. This means that you cannot use self-referential ON UPDATE
CASCADE or ON UPDATE SET NULL operations. This is to prevent infinite
loops resulting from cascaded updates. A self-referential ON DELETE
SET NULL, on the other hand, is possible, as is a self-referential ON
DELETE CASCADE. Cascading operations may not be nested more than 15
levels deep.
Source: InnoDB and FOREIGN KEY Constraints, Referential Actions
Implementing Cascade Delete in a self referencing table in EF Core 2
The problem solved by recursive method:
[HttpPost]
public async Task<JsonResult> DeleteComment([FromBody] DeleteCommentViewModel obj)
{
if (ModelState.IsValid)
{
var comment = await
_commentRepository.GetAll().SingleOrDefaultAsync(m => m.Id == obj.CommentId);
if (comment != null)
{
await RemoveChildren(comment.Id);
_commentRepository.Delete(comment);
}
if (Request.IsAjaxRequest())
{
return Json(1);
}
}
return Json(new { code = 0 });
}
async Task RemoveChildren(int i)
{
var children = await _commentRepository.GetAll().Where(c => c.ParentId = i).ToListAsync();
foreach (var child in children)
{
await RemoveChildren(child.Id);
_commentRepository.Delete(child);
}
}
How to set on delete cascade for self reference Foreign Key in Entity Framework in ASP.NET
i also faced the similar issue, and if i remember correctly what i found is EF doesn't support cassade delete on self reference, so we need to handle it by code. What i followed is
- Remove the cascade delete from fluent api or generated migration.
- Add code to delte/setnull all self-reference and then delete.
CASCADE Delete in many-to-many self-reference table
Read this KB article, which says the following among other things...
You receive this error message because in SQL Server, a table cannot
appear more than one time in a list of all the cascading referential
actions that are started by either a DELETE or an UPDATE statement.
For example, the tree of cascading referential actions must only have
one path to a particular table on the cascading referential actions
tree.
To do what you want, the DISPLAY_TAB_GROUPING table would have to appear twice. I suggest you use a stored proc that implements your delete code instead.
Related Topics
SQL Query on Multiple Databases
Group by Using Parameters in SQL
Performance of String Comparison VS Int Join in SQL
Executing Ssis Package with SQL Authentication
How to Ensure Integrity Between Unrelated Tables
SQL Server:Return Column Names Based on a Record's Value
Performance Tuning on Inner Join with Between Condition
Change the Size of Datatype in SQL
Access Db Update One Table with Value from Another
First Business Day of the Current Month - SQL Server
In MySQL, Find Strings with a Given Prefix
Get Every Hour for a Time Range
How to Get This Timestamp in the Format I Want, Oracle SQL
How to Return Last Inserted (Auto Incremented) Row Id in Hsql