My solution, mixing my ideas, some answers (Ron one from this thread, but also this and this for reflection) and trying to cover some different conditions.
It is based on EF6, but it should work fine, just fixing some extensions like GetTableName<TEntity>
.
My solution:
- uses extensions, so you only need
DbSet
to launch
- has a row count threshold, to decide between
RemoveRange
or SQL execution, to avoid perfomance issues
- the SQL version is based on
DELETE
instead of TRUNCATE
, to avoid foreign key issues (it has to fit your requirements, of course)
- has a parameter to save changes inline
private const int RangeLimit = 100;
private static void ClearTable<TEntity>(this DbSet<TEntity> dataSet, bool saveChanges = true) where TEntity : class
{
DbContext context = null;
if (dataSet.Count() > RangeLimit)
{
context = dataSet.GetContext();
context.Database.ExecuteSqlCommand($"DELETE FROM [{context.GetTableName<TEntity>()}]");
}
else
{
dataSet.RemoveRange(dataSet);
}
if (!saveChanges)
{
return;
}
if (context == null)
{
context = dataSet.GetContext();
}
context.SaveChanges();
}
private static DbContext GetContext<TEntity>(this DbSet<TEntity> dbSet)
where TEntity : class
{
var internalSet = dbSet
.GetType()
.GetField("_internalSet", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(dbSet);
var internalContext = internalSet?.GetType().BaseType
?.GetField("_internalContext", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(internalSet);
return (DbContext)internalContext?.GetType()
.GetProperty("Owner", BindingFlags.Instance | BindingFlags.Public)
?.GetValue(internalContext, null);
}
public static string GetTableName<TEntity>(this DbContext context) where TEntity : class
{
return (context as IObjectContextAdapter).ObjectContext.CreateObjectSet<TEntity>().EntitySet.Name;
}
All you have to do, with a database table named Entries
, is:
databaseContext.Entries.ClearTable();
if you want to save changes, or if you don't want:
databaseContext.Entries.ClearTable(false);
It is based on reflection, to simplify code. It has some performance tradeoff, of course, but reflection happens once for each table, hence should be completely acceptable in these conditions.