I've just managed to achieve this in my MVC application using the instructions and sample code from https://www.codeguru.com/csharp/csharp/soft-deleting-entities-cleanly-using-entity-framework-6-interceptors.html posted by Rakesh Babu Paruchuri on August 28th, 2015
The sample code link from that blog entry is https://github.com/rakeshbabuparuchuri/EFExpensionPoints
In case those links become unavailable here are the key points:
It uses a custom attribute "SoftDeleteAttribute" with an Entity Framework Interceptor.
The key elements that I included in my own project were:
- a class for the SoftDeleteAttribute inherited from System.Attribute
- a SoftDeleteQueryVisitor class that inherits from System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder.DefaultExpressionVisitor
- a SoftDeleteInterceptor class that inherits from System.Data.Entity.Infrastructure.Interception.IDbCommandTreeInterceptor
Then you register the interceptor - in my case I put the following code in the same file as my ApplicationDbContext (inherited from IdentityDbContext):
public class ApplicationDbConfiguration : DbConfiguration
{
public ApplicationDbConfiguration()
{
AddInterceptor(new Helpers.SoftDeleteInterceptor());
}
}
And override OnModelCreating to add a convention for dealing with the SoftDeleteAttribute:
var conv = new AttributeToTableAnnotationConvention<SoftDeleteAttribute, string>(
"SoftDeleteColumnName",
(type, attributes) => attributes.Single().ColumnName);
modelBuilder.Conventions.Add(conv);
The final step was adding the SoftDeleteAttribute to my ApplicationUser class.
[SoftDelete("IsDeleted")]
public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUser<int>
{
//some code removed to emphasise the important bit
[StringLength(150)]
public string Forenames { get; set; }
[StringLength(50)]
public string Surname { get; set; }
public bool IsDeleted { get; set; }
}
In addition to this I've also dropped and re-created the unique index on the Username column of my users table in the database so that it uses a condition so that I can re-use the usernames of deleted users (not recommended but I'm using an existing database):
CREATE UNIQUE NONCLUSTERED INDEX [UserNameIndex]
ON [dbo].[tbl_user] ([UserName] ASC)
WHERE ([IsDeleted]=(0))
I also ran some migrations - I'm not sure if that migrations step is important for getting it to work, I've literally only done this myself today so haven't had a chance to try it against a manually-created database.
With these changes I can soft-delete users and then create new users with the same username and/or email address
I also found a similar solution at http://marisks.net/2016/02/27/entity-framework-soft-delete-and-automatic-created-modified-dates/ which also uses command interceptors, but replaces the SoftDelete Attribute with a fixed column name and has the code arranged a little differently. He does also include updating Created and Modified columns as well as the soft-delete flag. That article references's Rakesh's article which helped me find it :)