Deleting Parent Entity of FK Constraint in Entity Framework & SQL Server - sql-server

I'm using Entity Framework with .NET 4.0 and SQL Server 2008.
I have two entities A and B, A has many B's (there's a field on B table, i.e. B->many to one ->A). When I try to delete a specific parent entity A, the query fails
A is parent entity, B is children entity.
Here's the code I use for deletion of a particular A entity:-
var obj = (from A in context.As where A.id=someValue select A).First();
context.As.DeleteObject(obj);
context.SaveChanges();
However it throws the famous exception
The DELETE statement conflicted with the REFERENCE constraint "FK_bs_as". The conflict occurred in database "myDb", table "dbo.bs", column 'a'.
The statement has been terminated.
Then I looked at the foreign key constraint using SQL Server Management Studio and edited FK as follows:
delete rule: cascade
update rule: cascade
enforce foreign key constraint: no
and tried to set FK to ON DELETE CASCADE. However obviously there's still a problem with it.
I don't want to fetch every damn child entity (B) of the parent entity (A) and delete them individually. That's too expensive when compared to executing a single SQL query.

What you need to do is:
Setting delete rule in the database as you did (don't set update rule and don't change enforcing constraints!)
Setting on delete rule on the relation in EDMX
The first step will ensure that cascade delete will work if your related entities are not loaded and second step will ensure that cascade delete delete will work if your related entities are loaded. Both steps are necessary.
Once you have this done you don't need to load related entities and delete them one by one.

Be sure that your entity model is in sync with the database model. Refresh your entity model every time you make changes to the database (update model from database), otherwise you can get unexpected exceptions.

Set in the association between A and B OnDelete to Cascade in EDMX
Generate Database from Model
Use the new model.edmx.sql to re-create the database
fill the database with your data
try again

Related

Generate custom EF6 code first migration SQL after foreign key constraints

I'm adding custom SQL to an EF6 code first migration. The SQL adds delete triggers to various tables. It's generating correct syntax and getting output as expected.
But the location of the output is giving me trouble. Code first migrations put all the foreign key constraints at the bottom of the generated SQL. When creating the constraints for a join table (used in a many-to-many association), the ON DELETE CASCADE clause is added. All fine and dandy, except when I've added a delete trigger to one of the tables participating in that relationship -- cascade delete isn't allowed coming from a table with a delete trigger on it.
Ideally, I'd like to do one of two things -- either move my SQL to the bottom of the script (where I can yank the cascade deletes off the constraints after they're added) or somehow tell EF not to cascade delete certain particular join tables, while leaving the default behavior in place for the more common case where the cascade deletes are the correct thing to do.
Anyone have a clue as to how this can be done?
Thanks.

Best practice for deleting many-to-many relationships with SQL Server and ASP.NET MVC

I'm working on a project in ASP.NET MVC using Entity Framework linked to a SQL Server database, to which I use SQL Server Management Studio to manage.
I have some many-to-many relationships that I handle with an intermediate table that links the two other tables. Let's say I have table A, table B and table A_B that links the A and B in a many to many relationship.
If I want to delete a row in table A, I must delete all rows in table B that links with it, therefore deleting the rows in A_B.
My question is:
What's the best practice in this case? Should I handle those deletes in the controller in MVC ASP.NET or must I handle this with a SQL Server trigger?
To me it would look cleaner to just use a trigger and abstracting all this logic from the controller itself, so I would only need to delete the row in table A and the lower lever (SQL Server) would take care of the rest.
But, I've heard people saying that we should avoid triggers in SQL Server, so in a commercial project, which approach would you recommend as being the best practice?
Thanks.
EDIT:
[TABLE A [id]] -> [ TABLE A_B [id_A, id_B, position] ] <- [TABLE B [id]]
That's the situation I have (I can't post images yet). I've tried to put Cascade on Delete on every relationship, but when I delete a row in A, the corresponding row in A_B get's deleted but not the corresponding table in B. Is there a way to do this? Or in this case I have to use triggers?
If you really want to force SQL Server to delete references you should use CASCADE DELETE not triggers, just because it's more obvious way to do it. You should switch on it on FOREIGN KEY creation.
If you already created the FOREIGN KEY then drop it first.
ALTER TABLE dbo.B
ADD CONSTRAINT FK_A_B_Cascade
FOREIGN KEY (AId) REFERENCES dbo.A(Id) ON DELETE CASCADE
But it's much better set your deletion logic in code. Because not in all cases you want to delete references. Sometimes it's better just set some flag like IsDeleted to true.
Moreover it's better not doing this in Controller, but create separate DAL (Data Access Layer) project and place it there. And can be that you want to use one of ORM like Entity Framework to access your DB.

Multi-tenancy: How do I delete a tenant?

I have a system with shared multitenancy, which means each table contains data for all tenants with a TenantId column to distinguish between them.
Provisioning a new tenant is quick and easy, however now I'm facing a challenge with deleting a single tenant.
Given that entities depend on each other for consistency, how do I delete a tenant easily from my database, while the system is in use by other tenants?
The system uses SQL Server 2008 R2, if that helps.
If I got you right - this is the classical case for use of FOREIGN KEYS with ON CASCADE option. You only delete one record from master tenants table and due to proper chain of FKeys the system deletes related records or updates the reference columns with NULL or DEFAULT value
Sometimes will not work in cases where table references itself with DELETE ON CASCADE
As Oleg has pointed out FK with ON CASCADE option should help. But since you haven't shown us the schema, I am not very sure whether there is a possibility of system throwing an error saying "Introducing FOREIGN KEY constraint causes cycles or Multiple cascade paths". If you see this error then may be instead of CASCADE DELETE add a INSTEAD OF DELETE trigger to do the job.
CREATE TRIGGER dbo.Tenants_Delete
ON dbo.Tenants
INSTEAD OF DELETE
AS
BEGIN;
--Delete from the Child and Master table as per your need here.
--Make use of the magic table DELETED
END;
Here's another approach: If deleting the tenant causes too much headache, you may be able to use a workaround.
Simply add a boolean column active to your tenant table. Then introduce a view that selects only the active tenants. Adjust your stored procedures to look up the data in this view rather than in the original tenant table.

Cascade Delete Use Case

I am pretty new to Business Analysis. I have to write requirements that show both (for now) cascade delete (for two tables) and the rest of the tables will delete explicitly.
I need some guidance for how to write the requirements for cascade deletion.
Delete child entities on parent
deletion.
Delete collection members if collection entity is deleted.
Actually it is hard to understand the task without context and also it smells like university/colledge homework (we had one very similar to this).
Use the ON DELETE CASCADE option to specify whether you want rows deleted in a child table when corresponding rows are deleted in the parent table. If you do not specify cascading deletes, the default behavior of the database server prevents you from deleting data in a table if other tables reference it.
If you specify this option, later when you delete a row in the parent table, the database server also deletes any rows associated with that row (foreign keys) in a child table. The principal advantage to the cascading-deletes feature is that it allows you to reduce the quantity of SQL statements you need to perform delete actions.
For example, the all_candy table contains the candy_num column as a primary key. The hard_candy table refers to the candy_num column as a foreign key. The following CREATE TABLE statement creates the hard_candy table with the cascading-delete option on the foreign key:
CREATE TABLE all_candy
(candy_num SERIAL PRIMARY KEY,
candy_maker CHAR(25));
CREATE TABLE hard_candy
(candy_num INT,
candy_flavor CHAR(20),
FOREIGN KEY (candy_num) REFERENCES all_candy
ON DELETE CASCADE)
Because ON DELETE CASCADE is specified for the dependent table, when a row of the all_candy table is deleted, the corresponding rows of the hard_candy table are also deleted. For information about syntax restrictions and locking implications when you delete rows from tables that have cascading deletes, see Considerations When Tables Have Cascading Deletes.
Source: http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.sqls.doc/sqls292.htm
You don't write use cases for functionality - that is the reason why it is hard to properly answer your question - we don't know the actor who interacts with the system and of course we know nothing about the system, so we cannot tell you how to write description of their interactions.
You should write your use cases first and from them derive the functionality.

SQL Server 2005 Cascading Delete

I'm not 100% sure how cascading deletes work.
I have for simplicity tables that look like this
User
User_ID
ExtendedUser
User_ID
Comments
User_Id
Posts
User_ID
I basically have a ton of tables which reference the User_ID from User. I'd like to set a cascading delete on one table so that I can delete the User object and ensure that all tables that reference User are deleted.
However, my understanding is that I need to set the delete action on every table that references User. that is I need to set the "cascade delete" on every child table. Is my understanding correct?
SQL Server Cascading
Update:
It looks like I have to set it for every relationship. Where should I think of these relationships as being "stored"? Maybe my conception is not right.
It looks like I can set all the referential integrity rules for each relationship using the management studio from the parent table.
For each relationship, you can specify what action to take.
Easiest way to manage this likely would be to use SQL Server Management Studio. Design your parent table, and find all the PK-FK relationships.
For each, choose which path to take when a Delete event occurs:
No Action - this would cause a FK error when it occurs
Cascade - delete the child record
Set null - the FK column value would be null'd. This would throw an err obviously when nulls aren't allowed in the child table.
Set default - if the FK column on the child table has a default, it would then be the new value in the child column.
What you are describing seems like bad mojo (especially if you don't enforce referential integrity). Consider the following:
You have 3 tables that reference the user table: Client, Employee and Guest
If I understand you correctly you are saying that when you delete a Client record that references a User record then you want that User record deleted as well (correct?).
If you do this and there are Employee and Guest records that reference that same user record then they will suddenly be pointing to nothing (if you don't enforce referential integrity).
It seems to me that if you have a bunch of tables that reference the User table then you should not do cascading deletes...

Resources