score:2
The solution you're looking for is to require entities have an IsDeleted
value of false
:
modelBuilder.Entity<Company>()
.Map( emc => emc.Requires( "IsDeleted" ).HasValue( false ) );
Now only companies with IsDeleted == false
will be retrieved from the DB
Update from comment:
modelBuilder.Entity<Company>()
.Map( emc =>
{
emc.MapInheritedProperties();
emc.Requires( "IsDeleted" ).HasValue( false );
} )
.Ignore( c => c.IsDeleted );
Update: test code which was successful (helper methods found here):
[Table("EntityA")]
public partial class EntityA
{
public int EntityAId { get; set; }
public string Description { get; set; }
public virtual EntityB PrimaryEntityB { get; set; }
public virtual EntityB AlternativeEntityB { get; set; }
public bool IsDeleted { get; set; }
}
[Table("EntityB")]
public partial class EntityB
{
public int EntityBId { get; set; }
public string Description { get; set; }
[InverseProperty("PrimaryEntityB")]
public virtual ICollection<EntityA> EntityAsViaPrimary { get; set; }
[InverseProperty( "AlternativeEntityB" )]
public virtual ICollection<EntityA> EntityAsViaAlternative { get; set; }
}
public partial class TestEntities : DbContext
{
public TestEntities()
: base("TestEntities")
{
Database.SetInitializer( new DatabaseInitializer() );
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<EntityA>()
.Map( emc =>
{
emc.Requires( "IsDeleted" ).HasValue( false );
} )
.Ignore( a => a.IsDeleted );
}
public override int SaveChanges()
{
foreach( var entry in this.ChangeTracker.Entries<EntityA>() )
{
if( entry.State == EntityState.Deleted )
{
SoftDelete( entry );
}
}
return base.SaveChanges();
}
private void SoftDelete( DbEntityEntry entry )
{
var entityType = entry.Entity.GetType();
var tableName = GetTableName( entityType );
var pkName = GetPrimaryKeyName( entityType );
var deleteSql = string.Format( "update {0} set IsDeleted = 1 where {1} = @id",
tableName,
pkName );
Database.ExecuteSqlCommand( deleteSql, new SqlParameter( "@id", entry.OriginalValues[ pkName ] ) );
entry.State = EntityState.Detached;
}
private string GetPrimaryKeyName( Type type )
{
return GetEntitySet( type ).ElementType.KeyMembers[ 0 ].Name;
}
private string GetTableName( Type type )
{
EntitySetBase es = GetEntitySet( type );
return string.Format( "[{0}].[{1}]",
es.MetadataProperties[ "Schema" ].Value,
es.MetadataProperties[ "Table" ].Value );
}
private EntitySetBase GetEntitySet( Type type )
{
ObjectContext octx = ( ( IObjectContextAdapter )this ).ObjectContext;
string typeName = ObjectContext.GetObjectType( type ).Name;
var es = octx.MetadataWorkspace
.GetItemCollection( DataSpace.SSpace )
.GetItems<EntityContainer>()
.SelectMany( c => c.BaseEntitySets
.Where( e => e.Name == typeName ) )
.FirstOrDefault();
if( es == null )
throw new ArgumentException( "Entity type not found in GetTableName", typeName );
return es;
}
public DbSet<EntityA> EntityAs { get; set; }
public DbSet<EntityB> EntityBs { get; set; }
}
Application code:
class Program
{
static void Main(string[] args)
{
using( var db = new TestEntities() )
{
var a0 = new EntityA()
{
EntityAId = 1,
Description = "hi"
};
var a1 = new EntityA()
{
EntityAId = 2,
Description = "bye"
};
db.EntityAs.Add( a0 );
db.EntityAs.Add( a1 );
var b = new EntityB()
{
EntityBId = 1,
Description = "Big B"
};
a1.PrimaryEntityB = b;
db.SaveChanges();
// this prints "1"
Console.WriteLine( b.EntityAsViaPrimary.Count() );
db.EntityAs.Remove( a1 );
db.SaveChanges();
// this prints "0"
Console.WriteLine( b.EntityAsViaPrimary.Count() );
}
var input = Console.ReadLine();
}
}
score:0
You can do soft delete like this:
- In OnModelCreating add an IsDeleted discriminator to every entity that can be soft deleted
- Override SaveChanges and find all the entries to be deleted
- Run SQL on these entries to set the IsDeleted discriminator then set their state to "detached"
- Change any unique indexes to ignore any soft deleted records
You can find working code at this answer: How to soft delete using Entity Framework Code First
And that code was picked up by this Blog: http://netpl.blogspot.com/2013/10/soft-delete-pattern-for-entity.html
score:0
Four years later, I finally stumbled on a library that does exactly what I want.
EntityFramework.DynamicFilter.
modelBuilder.Filter("IsDeleted", (ISoftDelete d) => d.IsDeleted, false);
The above snippet ensures that the soft-deleted items are not retrieved. This affects both direct queries (db.Set<Foo>().ToList()
) and indirect loadaed entities db.Set<Foo>().Include(e => e.Bars).ToList()
), thus completely hiding the soft deleted entities from view.
For completeness' sake, I've combined this with an override to SaveChanges()
which converts hard deletes to soft deletes before committing to the database.
This means that developers are able to safely use hard delete logic, and they'll never even realize that the context is using soft deletes. They don't need to know, they don't need to care, they can't forget to implement it the right way, they never need to write a check for the IsDeleted
flag.
Source: stackoverflow.com
Related Articles
- LINQ Source Code Available
- creating Linq to sqlite dbml from DbLinq source code
- Make access possible to dynamic table LINQ EF6 Code First
- Is it possible to have one LINQ in one line of code for
- How to handle nulls in this LINQ Code using a possible null List?
- source code for LINQ 101 samples
- Include null cells in Linq query from DB in C# code
- c# Linq or code to extract groups from a single list of source data
- Convert string[] to int[] in one line of code using LINQ
- Code equivalent to the 'let' keyword in chained LINQ extension method calls
- EF LINQ include multiple and nested entities
- Linq code to select one item
- FindAsync and Include LINQ statements
- How are people unit testing code that uses Linq to SQL
- LINQ Include vs Join. Are they equivalent?
- Is it possible to handle exceptions within LINQ queries?
- How to select multiple values from a Dictionary using Linq as simple as possible
- C# linq include before-after where
- Is it Possible to call a Stored Procedure using LINQ in LINQPad?
- Where to draw the line - is it possible to love LINQ too much?
- conditional include in linq to entities?
- How is it possible that "RemoveAll" in LINQ is much faster than iteration?
- Is it possible to use Linq to get a total count of items in a list of lists?
- Include nested entities using LINQ
- LINQ query to perform a projection, skipping or wrapping exceptions where source throws on IEnumerable.GetNext()
- Filtering include items in LINQ and Entity Framework
- Is an outer join possible with Linq to Entity Framework
- Why doesn't LINQ include a `distinct` keyword?
- Is it possible to express this code in LINQ?
- EF 6 - Include Why Do I not have linq choice?
- Nested Linq Min() crashes Visual Studio
- How do I use LINQ to compare one value from its previous value?
- Linq OrderBy not sorting correctly 100% of the time
- How do I take last n elements from nested collection
- LINQ .Any() iterator for 2D Array - [,]
- 'Model' does not contain a definition for 'Object"
- How to call List in LINQ?
- C# LINQ query shows and exception when datagridview cell is empty
- How to OrderBy ASC or DESC a specific column in LINQ according to parameters
- C# Using Enumerable Range and Except with custom class to determine missing sequence number
- ExecuteStoreQuery with Dbcontext
- C# String Splitting of a path to get every sub path
- C# Search filters- ignore specific diacritics
- Order by from another context
- Using LINQ to query three entitites. - Include path expression must refer to a navigation property defined on the type
- Combine two different types into one linq query and sort it
- Linq + Where + abstract method = LINQ to Entities does not recognize method
- Copy subset of items from one RadComboBox to another
- Raven DB LINQ Where->Any Query not working
- Linq to Sql - Set connection string dynamically based on environment variable