Cascading
means that upon deleting a main entity, child-entities are deleted too.
Entities
can be automatically Deleted
along with other Entities
. But if they are not inherently part of the main Entity
, they would be Unlinked
instead.
This can be implemented as a pattern in C#
. A reason to do it in C#
, is to explicitly see in the code, that the other Deletions
take place. It may be important not to hide this from view.
One way to implement Cascading
, is through extension methods:
DeleteRelatedEntities
and UnlinkRelatedEntities
.
Here is a suggestion for how to organize the Cascading
code.
In the csproj
of the Business
layer, you could put a sub-folder called Cascading
and put two code files in it:
JJ.Ordering.Business.csproj
|
|- Cascading
|
|- DeleteRelatedEntitiesExtensions.cs
|- UnlinkRelatedEntitiesExtensions.cs
Here is how DeleteRelatedEntitiesExtensions.cs
might look internally:
/// <summary>
/// Deletes child entities inherently part of the main entity.
/// </summary>
public static class DeleteRelatedEntitiesExtensions
{
public static void DeleteRelatedEntities(this Order order)
{
...
}
}
In there, child Entities
are successively Deleted
:
public static class DeleteRelatedEntitiesExtensions
{
public static void DeleteRelatedEntities(this Order order)
{
// Delete child entities.
foreach (var orderLine in order.OrderLines.ToArray())
{
_repository.Delete(orderLine);
}
}
(Note: The ToArray
can prevent an Exception
about the loop collection being modified.)
Before an extension method Deletes
a child Entity
, it might call Cascading
upon the child Entity
too:
public static void DeleteRelatedEntities(this Order order)
{
foreach (var orderLine in order.OrderLines.ToArray())
{
// Call cascading on the child entity too!
orderLine.UnlinkRelatedEntities();
_repository.Delete(orderLine);
}
}
UnlinkRelatedEntities
might be a little bit easier. It neither requires Repositories
not does it do much recursion:
/// <summary>
/// Unlinks related entities, not inherently part of the main entity.
/// </summary>
public static class UnlinkRelatedEntitiesExtensions
{
public static void UnlinkRelatedEntities(this OrderLine orderLine)
{
orderLine.UnlinkOrder();
orderLine.UnlinkProduct();
}
}
Note that it uses the Unlink
pattern discussed earlier.
The Cascading
extension methods delete related Entities
, not the main Entity
. The idea behind that is: Where a main Entity
is Deleted
, we could call the Cascading
methods first:
entity.DeleteRelatedEntities();
entity.UnlinkRelatedEntities();
// Delete main entity separately.
_repository.Delete(entity);
That way we can see explicitly that more Deletions
take place.
The DeleteRelatedEntities
methods might need Repositories
to perform the Delete
operations.
You could pass these Repositories
as parameters:
public static void DeleteRelatedEntities(
this Order order,
/* Repository parameter */
IOrderLineRepository repository)
{
foreach (var orderLine in order.OrderLines.ToArray())
{
orderLine.UnlinkRelatedEntities();
repository.Delete(orderLine);
}
}
Or you might make repositories available through a technique called dependency injection.
Itβs up to you. The choice to use extension methods was also a matter of preference.
Sometimes an Entity
indeed has related Entities
to Cascadedly
Unlink
or Delete
, but sometimes it doesnβt, creating subtleties in the implementation.
Instead of using C#
to perform the Cascading
you could also configure the database to do it for you. You could use Triggers
or Delete Actions
for that.
But this might not play along nicely with our data access technology of choice: ORM
. Saving the changes could then complain about too many records modified, because more records were affected than the ORM
expected.
You can also configure the ORM
through Mappings
to automatically handle the Cascading
.
A downside of this might be, that the deletions are hidden away from view. It may surprise programmers, when related data is automatically deleted. This can result in unintended consequences, taking away control from the programmer.
Hopefully this gave a good impression of how you could build up Cascading
code by just using a pattern in C#
.