As I understand, if I delete a parent row, its children should be deleted if I turn on cascade on delete. However, from my testing, it doesn't seem to work at all. No matter if I set WillCascaseOnDelete to true or false, it simply sets the foreign key of its children to null. This is causing another problem that I have to set the foreign key nullable, otherwise, SaveChange will throw exception. Is this a defect or desired behavior?
This is because your foreign keys (child) are nullable. By default, when deleting parent, if the foreign key on the relationship is nullable EF will delete the parent and set the foreign key to null. If the foreign key is NOT NULL it will delete the child (the behaviour you're looking for?).
You can alter this default behaviour here
Make sure on the Foreign Key Relationship window in SQL Server, you have selected Cascade as Delete rule.
Related
If I have an object called Project that has a property called Creator and creator is a complex type, EF will automatically use the value null if the Creator property has not been assigned. Is it possible to instead use 0 instead of null in the database fields?
No, that would break Foreign Key Constraints on the database side, since there wouldn't be a Creator row with a primary key of 0 for the Project row's foreign key to point to.
In a relational database, at least those that respect foreign key constraints, every relationship between rows is represented as a pair of primary, and foreign keys. The database is designed to enforce that a foreign key always points to a valid primary key. It will prevent you from updating a FK field to a value that doesn't exist in the PK field. It will also yell at you for trying to delete the row that contains the PK as long as the FK still points to it (unless cascade-delete is turned on, but that gets complicated).
In theory, Entity Framework could probably be forced in to trying to do what you want, but the database would reject it, and EF would almost certainly have issues trying to retrieve rows with the 0/null value in it if it is configured to include navigation properties.
Entity Framework 6 Casscading Deletes and DropForeignKey fails on auto generated constraint name
I've been running into a bit of an issue with Entity Framework and cascade deletes between two tables on several one-to-many relationships.
Initially it looked like the correct path to take was to configure the table mappings with the OnModelCreating method of DbContext turning off cascade delete in a manner such as
modelBuilder.Entity<SourceTable>()
.HasOptional(x => x.NavigationProperty)
.WithOptionalDependent()
.WillCascadeOnDelete(false);
This however did not work throwing an exception stating
Cannot delete or update a parent row: a foreign key constraint fails...
More research lead me to believe that this is because all affected entities must be loaded into the context (eager fetched) so that entity framework may set the FK references to null as part of the transaction. This is not practical for my needs based on the size of the relational graph I'd be dealing with.
My next approach was to modify the Seed method of the Configuration class and run some arbitrary SQL to drop the Foreign Key constraint and re-add it as a ON DELETE SET NULL constaint. This worked in most cases, however one of the consraints has what appears to be an auto generated unpredicatable name that is diffrent on each call of Update-Database. Given that the name can't be predicted the ALTER statments aren't particualr helpful
context.Database.ExecuteSqlCommand(#"ALTER TABLE SourceTable DROP FOREIGN KEY FK_9405957d032142c3a1227821a9ed1fdf;
ALTER TABLE SourceTable
ADD CONSTRAINT FK_ReasonableName
FOREIGN KEY (NavigationProperty_Id) REFERENCES NavigationProperty (Id) ON DELETE SET NULL;");
Finally, I've taken the apprach to use the migration functionality (DbMigration) and override Up method and leveraging the DropForeignKey method along side more explicit SQL to re-add the constraint (EF does not appear to provide a factility to create a ON DELETE SET NULL constraint).
DropForeignKey("SourceTable", "NavigationProperty_Id", "DestinationTable");
Sql("ALTER TABLE SourceTable ADD CONSTRAINT FK_ReasonableName FOREIGN KEY (NavigationProperty_Id) REFERENCES DestinationTable (Id) ON DELETE SET NULL;");
This works great, up until I encounter the constraint with the auto generate name. At this point the DropForeignKey method fails with an exception that is swallowed up by
System.Runtime.Serialization.SerializationException: Type is not resolved for member 'MySql.Data.MySqlClient.MySqlException,MySql.Data...
When dumping the migration to a SQL script file it becomes clear that the DropForeignKey simply generates a FK with a more predictable, non-ambiguous byte stream array.
Is there a proper EF Code First approach to solve the problem of setting FK column values to null when deleting the refrenced row, or am I stuck having to hand code SQL in order to gain this functionality?
How to set FOREIGN KEY (packet_id) REFERENCES girvi_packet(id) DEFERRABLE INITIALLY DEFERRED to NULL ?
If parent get deleted postgreSQL raises error that parent is missing I want to suppress this behavior. This constraint is added by default by some 3rd part tool. But my use case demands otherwise.
The purpose of the foreign key is to prevent orphan children. The only way you can do is to delete the constrain
ALTER TABLE ... DROP CONSTRAINT ...
I have the following class
public class ObjectA{
private List<ObjectB> list;
}
ObjectA and ObjectB are in 1:N relation.
I want to delete some of ObjectB instances and I use:
while (objectA.list.Any())
objectA.list.Remove(objectA.list.First());
List is of the relation table -
List<ObjectAobjectB>
In the Database I have defined therelation as a nullable foreign key otherwise I get
The operation failed: The relationship could not be changed because one or more of
the foreign-key properties is non-nullable. When a change is made to a relationship,
the related foreign-key property is set to a null value. If the foreign-key does not
support null values, a new relationship must be defined, the foreign-key property
must be assigned another non-null value, or the unrelated object must be deleted.
So now that it is Nullable foreign key,
When I run sql profiling I get the following:
exec sp_executesql N'update [Schem].[ClassB]
set [ClassAID] = null
where ([Id] = #0)
',N'#0 uniqueidentifier',#0='092CE959-370A-4785-AF4A-93A0E4952C59'
It just enters a null in the relation instead of deleting the object.
What am I doing wrong?
Thanks.
objectA.list.Remove(objectA.list.First()); is removing the relationship, not the actual entity. If you want to delete the objectB's from the database then you have to remove them from the context like so:
foreach(var item in objectA.list.ToList())
context.ObjectBs.Remove(item);
I think it is a case of Cascade Delete.
I'm not sure but I think you can set the cascade delete (in your application AND in your database) to allow EF to make deletion on cascade.
Maybe look at some documentation to find how to do that. It seems there is a lot of related questions on SO.
Example
Example2
Example3
In my database, I have a number of objects that can be related to each other.
This is fine, until I decide I want to delete these objects. Because of the relation record, I need to implement cascade delete to prevent an exception from being thrown.
When an object that is on either side of the relation is deleted, I want the relation record to be deleted too. I would like to create a database structure that looks like this:
CREATE TABLE [MyObject]
(
[ID] [int] IDENTITY PRIMARY KEY,
...
);
CREATE TABLE [MyObjectRelation]
(
[ID] [int] IDENTITY PRIMARY KEY,
[MyObjectID] [int] FOREIGN KEY REFERENCES [MyObject] ([ID]) ON DELETE CASCADE,
[RelatedMyObjectID] [int] FOREIGN KEY REFERENCES [MyObject] ([ID]) ON DELETE CASCADE
)
However, whenever I attempt to run this on my database, I receive this error message:
Introducing FOREIGN KEY constraint '...' on table 'MyObjectRelation' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I have read the documentation about this, but I do not see how this layout could cause a cycle. It is entirely possible of course, that I have misinterpreted the documentation on MSDN for cascade delete, and the database layout above will not achieve what I want here.
I would be very interested in hearing what I can do to implement the behaviour that I want.
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.
You can use triggers to achieve the same behavior.