How do I perform cascading deletes with EF4? - c#

On a previous project we had EF4 performing cascading deletes (Delete a parent record and the child records are deleted, too). On this project (different company), EF4 is not performing cascading deletes. What do I need to do to make EF4 perform a cascading delete?

Using just EF4's cascading delete is not enough; you should set up cascading deletes on your database as well, in case not all children are loaded into the object context. That being said, the cascade delete properties are set on the assocation. Go to the model browser, select an assocation and view properties.

I am on the same boat. I only have cascade on delete in EDM/EF4 and not (yet) in the database. Try this...
In the relationship, set the OnDelete of parent's end (1 multiplicity) to Cascade . Then in your code load all children before saving the changes (deletion).
var parent = context.Parents.SingleOrDefault(p => p.Id == parentId);
parent.Children.Load();
if (parent != null)
{
context.Parent.DeleteObject(parent);
context.SaveChanges();
}

You have two ways of cascade deleting implementation:
Set up it on the database layer (triggers or relationships)
Try to use extension methods. You can define delete logic for current table and call methods for related table updating.

Related

How do you delete a single record from EF, when you're using generics?

I'm having a problem in which the deletion of a record in a table works, but only so long as the table has no child foreign key relationships. Now, when we have a parent table and want to delete the record using EF, it fails with an error of, "The relationship could not be changed because one or more of the foreign-key properties is non-nullable." I've deleted cascading delete on the child table referencing the parent table. I've tested it within SSMS. It works fine. But from within C# it fails. We have a view model where we've defined a generic DeleteRow method. This works great, so long as the row being deleted has no child tables. It fails, if the table is a parent table. I tried looking here on Stackoverflow for an answer and came across this question, now closed: stackoverflow.com/questions/17723276/delete-a-single-record-from-entity-framework. The answer to this question used a discrete table in EF. We're using generics. Here's our code:
public void DeleteRow(T row)
{
if (App.MainDataContext != null && row != null)
{
App.MainDataContext.Entry<T>(row).State = EntityState.Deleted;
App.MainDataContext.SaveChanges();
}
}
I don't believe setting the State property to the enumeration EntityState.Deleted is working, as that's only setting it for the record in the parent table, not for any of the related records in the child tables. (MainDataContext is entity from a .EDMX file.) How do we delete a single record from any table using EF 6 when we're using generics to pass in the table type?
The problem is that when you set the state to deleted, the related entity is also loaded (tracked by the context's change tracker). When you delete your row, EF tries to set the parent navigation property to null, but it is a not nullable relationship.
To solve this you have to set a cascading delete in the relationship in you model (EDMX), not only in the database.
It should work also, if by the instance of your context the related entity is not tracked. In this case on SQL-Server side the cascading delete should work.

How to delete on cascade with when the database has not this set?

I have a SQL Server database that has two tables with a 1:N relationship. In the relationship I have set the on delete, do nothing, because in general I want to control this in the logic business, I mean, in my repository.
So in my repository I get the rows that I need to delete from both tables, and in theory I get all the parents rows of the main table that are parents of the rows of the child table. So I would have no problems.
But I know that when I do saveChanges, EF not ensure the order of the deletings, so it is possible that try to delete a parent before deleting all the childs, so this is the problem.
So my quesetion is if there is any way to configure the dbContext, the relation of both entities to delete the rows without this problem?
My code is:
using(MyEntities myDbContext = new myEntities())
{
//Here I could configure myDbContext to perform a correct deleting?
//code to get the rows to delete
myDbContext.SaveChanges(); //here is the error.
}
Thank you.
The entity should contain a navigation property of the entity/table that it's related to. Assuming table a was the parent table, you would then delete all the record(s) in the navigation property that points to the child table/table b. Then you would delete the record(s) from table a. Then call myDbContext.SaveChanges() and EF would take care of all the cascade on delete stuff for you.

Is it possible to specify child objects that should also be deleted with their parents in Linq?

In order to make sure that all child elements are deleted, I am currently having to do this:
ComponentType type = db.ComponentTypes.First(t => t.ID == Convert.ToInt32(button.CommandArgument));
db.RigActions.DeleteAllOnSubmit(type.Components.SelectMany(c => c.RigActions));
db.Components.DeleteAllOnSubmit(type.Components);
db.ComponentTypes.DeleteOnSubmit(type);
db.SubmitChanges();
For maintainability purposes, this is scaring me that I (or another developer) might overlook all of the cleanup necessary when a parent (or in this case - a parent of a parent) element is deleted.
Does Linq have any type of dependency property I can set so that when a Component type is deleted, it deletes all component records, and all actions belonging to each component record?
I'm not sure it can be done in Linq (it probably can). It would be far easier if you defined a CASCADE DELETE on your database though. That way, child records would be deleted automatically and you'd not need to worry about forgetting anything.
This article might give you a bit more information
http://www.mssqltips.com/sqlservertip/2743/using-delete-cascade-option-for-foreign-keys/
This article is about setting up cascade delete within EF
Entity Framework on delete cascade

Entity Framework - Deleting Complex Object

I'm have the following Entity Framwork objects:
Evaluation, Stage, Apartment
Evaluation contains many Stages and Stage contains many Apartments.
I'm trying to deleted a certain stage as follows:
var deletedStages =
originalEvaluation.Stages.Where(s => s.State == StateTypes.Deleted);
deletedStages.ToList().ForEach(stage =>
{
stage.Apartments.ToList().ForEach(
apartment => stage.Apartments.Remove(apartment)
);
originalEvaluation.Stages.Remove(stage);
});
deletedStages.ToList().ForEach(stage =>
{
stage.Apartments.ToList().ForEach(apartment =>
shechtmanEntities.Apartments.DeleteObject(apartment)
);
shechtmanEntities.Stages.DeleteObject(stage);
});
}
}
try
{
shechtmanEntities.SaveChanges();
}
But I'm keep getting an Exception : "The relationship could not be changed because one or more of the foreign-key properties is non-nullable".
I know it has to do with a null foreign-key, but I can't understand which? and Why?
Thanks.
If you cannot Cascade Delete (SQL server can be funny about that: https://stackoverflow.com/a/6065583/613004) asdutzu suggests, then:
If it's one-to-many relationship (sounds like it is), then you'll need to manually delete each child object and save-changes before deleting the parent. I.E. delete the apartment (or re-assign it to another Stage), then delete the stage, and so on.
Otherwise, if it's many-to-many, and the joining table is exposed through the entity model, delete the joins between the stages and apartments first, then delete the stage. If not, then detach the apartment from the stage and save changes before deleting the stage.
Try just deleting the Evaluation or Stage and rely on a Cascade Delete to remove it's children entities (in your case Apartments) rather than removing them each individually.

Entity Framework Cascading Deletes & Lazy Loading

I am using the Northwind sample database. I have this code:
var db = new NorthwindEntities();
int id = 2; // Example
var delObject = (from o in db.Orders.Include("Order_Details")
where o.OrderID == id
select o).First();
db.Orders.DeleteObject(delObject);
db.SaveChanges();
I have an (1-to-many) association in Order - Order Details, with cascading deletes. (If I delete one Order, all Order_Details with the same OrderID will be deleted).
I have LazyLoading enabled.
If I delete the .Include("Order_Details") in the from clause, the cascade delete won't work.
Why does this happen? Isn't lazy initialization supposed to "include" the Order_Details for me, and eventually let me cascade delete?
The cascading deletes is defined in your EF model.
EF will therefore generate delete statements for data that it has loaded. EF will not go to the database to check what it should delete.
You can define cascading deletes (depending on your database) at the database level. In this case EF will delete the top node and the database will delete the related rows.
Do you have the cascading delete defined in both the database and the entity configuration? I've seen where having it defined in only one and not the other can cause this problem.
Cascade deletions in EF model deletes only those details which has been loaded in context. In case if you do use Include Order_Details are loaded during query along with Orders. If you enabled LazyLoading and not use Include then they are loaded on as needed basis, i.e. when you reference navigation properties.
Thus if you don't care about details and agree that they will be silently deleted with master record you have to define cascade deletion both in EF model and DB schema.

Categories

Resources