find and solve || findandsolve.com
Please wait.....

EF Core Soft Delete Cascade | Entity Framework Core


In the entity framework soft Delete feature allows you to flag entities as Soft Delete instead of deleting them Hard Delete.Soft deletes aren't really deletes from the database,It's instead a IsDeleted flag marked on the specific row. Soft delete is just a term and it doesn't actually delete the row, but only updates a single column value, so no related entities are affected with this. However, we can do this with either entity framework or SQL trigger. 

Soft deleting involves something along the lines of adding an DateleteDate attribute which is usually contains value DateTime representing when the data was deleted to the database table that represents the  soft delete. 


In the given below example, I will be using a sample .NET 5 Core project to store EntityItems, EntityOrders and EntityOrderItems for a sample store. Initially,Controller will provide Item DELETE endpoint and it will actually delete the record from the database, but when update the solution EntityFrameworkCore.Triggered from NuGet package to setup triggers specific entity when it changes state to delete and instead mark the flag property and not actually delete from the database record.

Soft-delete solution example

Now, I am goint to create NET 5 Core solution which simply deletes the Item from the entity. There are three main entity models that we store in out database like as given below.

 public class EntityItem  
 {  
  public int ItemId{ get; set; }  
  public string Name { get; set; }  
  public int DisplayOrder { get; set; }  
  public virtual ICollection<EntityOrderItem> EntityOrderItem { get; set; }  
 }  
public class EntityOrder  {    public int OrderId{ get; set; }    public DateTime CreateDate{ get; set; }
   public ICollection<EntityOrderItem> EntityOrderItem { get; set; }
 }  
public class EntityOrderItem
 {
  public int OrderItemId {get;set;}
  public int OrderId { get; set; }
  public int ItemId { get; set; }
  public int Quantity { get; set; }
  public virtual EntityItem EntityItem { get; set; }
  public virtual EntityOrder EntityOrder { get; set; }
  }  

I am going to  creat an endpoint to delete Item directly from the Controller like  as give below.


public class EntityItemController : Controller  
{
    readonly DataContext _dataContext;
    public EntityItemController(DataContext  dataContext)
    {
        _dataContext= dataContext;
    }
    [HttpGet]
    public IActionResult Get()     {
      return _dataContext.EntityItem.Where().ToList();
    }
   [HttpDelete]
    public IActionResult  Delete(int id)
    {
        var item = _dataContext.EntityItem.Where(x=>x.ItemId==id).FirstOrDefault();
         if (item != null) {
            _dataContext.EntityItem.Remove(item);
        _dataContext.SaveChanges(); }
    }

Now first am going to run the tool create and include data seeding file.

seeding add "AddInitialEntityOrderItem" -o Seedings

And then I added the following SQL script and run this code like as given below.

DECLARE @computerId INT
INSERT INTO EntityItem([Name], [DisplayOrder]) Values ('Dell Core 7', 1)
SET @computerId = @@IDENTITY
DECLARE @ramId INT
INSERT INTO EntityItem([Name], [DisplayOrder]) Values ('8GB',2)
SET @ramId = @@IDENTITY
DECLARE @orderId INT
INSERT INTO EntityOrder(CreateDate) values (GETUTCDATE())
SET @orderId = @@IDENTITY
INSERT INTO EntityOrderItem(OrderId, ItemId, Quantity) Values (@orderId, @computerId ,3)
INSERT INTO EntityOrderItem(OrderId, ItemId, Quantity) Values (@ramId , @keyboardId, 1)
 

Handle Soft Delete Trigger

To introduce soft-delete functionality without actual change in the delete method, I will first add reference to EntityFrameworkCore.Triggered from nuget package.

dotnet add package EntityFrameworkCore.Triggered 

Write out triggers before is to mark entities that we would like to form soft-deleteable. I will simple do that with an interface which can also force the implementation of deleted flag property.

I decided to possess deleted flag stored as nullable DateTime, in order that once we have the worth present we all know that item is deleted and that we also know the time soft delete action occurred.

public interface ISoftDelete
{
  public DateTime? DeletedDate { get; set; }

Now I want to implement this ISoftDelete interface for each entity we want to apply soft-delete to. In  this will be EntityItem entity so therefore I need to reference and implement this interface.

 public class EntityItem : ISoftDelete
 {
  public int ItemId{ get; set; }
  public string Name { get; set; }
  public int DisplayOrder { get; set; }
  public virtual ICollection<EntityOrderItem> EntityOrderItem { get; set; }
 }  

There is another thing to try to to before we introduce the trigger which is creating and running the migration for the newly updated entity. Once the migration is executed, we'll have the new column in our Items table.

public class SoftDeleteTrigger : IBeforeSaveTrigger<ISoftDelete>  
{
    readonly DataContext _dataContext;
    public SoftDeleteTrigger(DataContext dataContext)
    {
        _dataContext = dataContext;
    }
    public async Task BeforeSave(ITriggerContext<ISoftDelete> context, CancellationToken cancellationToken)
    {
        if (context.ChangeType == ChangeType.Deleted)
        {
            var entry =_dataContext.Entry(context.Entity);
            context.Entity.DeletedDate= DateTime.UtcNow;
            entry.State = EntityState.Modified;
        }
        await Task.CompletedTask;
    }
}  

This trigger will now be hit whenever there's a change on any entity which implements ISoftDelete interface. This basically means if there's a requirement to introduce soft delete for the other entity, all we'd like to to is to implement this interface within the entity class and run the migration in so that we've the new field created as a column within the database.

I you check out the code of the trigger class, you'll see that it's quite simple. If change type is deleted, we just assign the present date time to DeletedOn property and that we switch the entity state to Modified in order that EF doesn't delete the entity once we perform saving of changes.

And the last step is to register triggers to Dependency Injection in Startup.cs class. We can register one by one trigger with extensions that come as part of EntityFrameworkCore.Triggered package.

services.AddDbContext<DataContext>(options =>  
{
    options.UseSqlServer(Configuration.GetConnectionString(DbContextConfigConstants.Configura_Connection_Name),
        x =>
        {
            x.MigrationsHistoryTable("__EFMigrationsHistory");
            x.MigrationsAssembly(this.GetType().Assembly.GetName().Name);
        }
    );
    options.UseTriggers(triggerOptions => {
    triggerOptions.AddAssemblyTriggers();  


EF Core hard delete

In Entity Framework Core (EF Core), you can perform a hard delete by calling the Remove method on a DbSet instance for the entity you want to delete. The following is an example of how to perform a hard delete using EF Core:

using (var context = new YourDbContext()) { var entityToDelete = context.YourEntity.Find(id); context.YourEntity.Remove(entityToDelete); context.SaveChanges(); }

In this example, YourDbContext is the class that represents the database context, YourEntity is the DbSet for the entity you want to delete, and id is the primary key of the entity. The Find method is used to retrieve the entity to delete, and the Remove method is called to delete the entity. Finally, SaveChanges is called to persist the changes to the database.

Note that with this approach, the entity will be permanently deleted from the database and cannot be recovered. If you need to implement soft delete instead, you can add a "deleted" flag to your entity and modify your delete logic to set the flag instead of calling the Remove method.


Entity Framework delete by ID

In Entity Framework, you can delete an entity by its ID by using the Remove method on a DbSet instance for the entity you want to delete. You first need to retrieve the entity from the database using the Find method, then call the Remove method on the retrieved entity. Finally, call the SaveChanges method to persist the changes to the database.

Here is an example of how to delete an entity by its ID in Entity Framework:

using (var context = new YourDbContext()) { var entityToDelete = context.YourEntity.Find(id); context.YourEntity.Remove(entityToDelete); context.SaveChanges(); }

In this example, YourDbContext is the class that represents the database context, YourEntity is the DbSet for the entity you want to delete, and id is the primary key of the entity. The Find method is used to retrieve the entity to delete, and the Remove method is called to delete the entity. Finally, SaveChanges is called to persist the changes to the database.

Note that with this approach, the entity will be permanently deleted from the database and cannot be recovered. If you need to implement soft delete instead, you can add a "deleted" flag to your entity and modify your delete logic to set the flag instead of calling the Remove method.


Entity framework delete without primary key

In Entity Framework, you can delete an entity without a primary key by first retrieving the entity using a LINQ query, then calling the Remove method on the retrieved entity. Finally, call the SaveChanges method to persist the changes to the database.

Here is an example of how to delete an entity without a primary key in Entity Framework:

using (var context = new YourDbContext()) { var entityToDelete = context.YourEntity.Where(e => e.SomeProperty == someValue).FirstOrDefault(); context.YourEntity.Remove(entityToDelete); context.SaveChanges(); }

In this example, YourDbContext is the class that represents the database context, YourEntity is the DbSet for the entity you want to delete, and someValue is a value of a property that can be used to identify the entity. The LINQ Where method is used to retrieve the entity to delete, and the Remove method is called to delete the entity. Finally, SaveChanges is called to persist the changes to the database.

Note that if multiple entities match the condition in the LINQ query, only the first entity will be deleted. If you need to delete multiple entities, you can modify the LINQ query to return a collection and then call the Remove method on each entity in the collection.


Entity without primary key Hibernate

In Hibernate, it is possible to have an entity without a primary key, but it's not recommended as it can lead to difficulties when managing the entities and their relationships. A primary key is used as a unique identifier for an entity, and it's essential for the correct functioning of Hibernate's persistence mechanism.

If you still need to have an entity without a primary key in Hibernate, you can use a combination of natural keys and/or business keys to identify the entity. Natural keys are unique properties of the entity that can be used as an identifier, and business keys are a combination of properties that identify the entity.

Here is an example of how to map an entity without a primary key in Hibernate:

@Entity public class YourEntity { // Properties @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long id; @NaturalId private String property1; @NaturalId private String property2; // Getters and setters }

In this example, the entity YourEntity has two natural keys, property1 and property2. The @NaturalId annotation is used to specify the natural keys, and the @Id annotation is used to specify a primary key for the entity. The primary key is generated using a sequence generator and can be used to identify the entity in Hibernate's persistence mechanism.

When you want to delete an entity without a primary key in Hibernate, you first need to retrieve the entity using a query that matches the natural keys or business keys, and then call the delete method on the entity.

Here is an example of how to delete an entity without a primary key in Hibernate:

Session session = sessionFactory.openSession(); session.beginTransaction(); YourEntity entity = (YourEntity) session.byNaturalId(YourEntity.class) .using("property1", property1Value) .using("property2", property2Value) .load(); session.delete(entity); session.getTransaction().commit(); session.close();

In this example, the entity is retrieved using the byNaturalId method on the Session instance, which allows you to retrieve an entity using its natural keys. The delete method is then called on the retrieved entity to delete it from the database. Finally, the transaction is committed, and the session is closed.

Related information

Sundar  Neupane

Sundar Neupane

I like working on projects with a team that cares about creating beautiful and usable interfaces.

If findandsolve.com felt valuable to you, feel free to share it.

Comments



Report Response