目录
背景
扩展助手
先决条件
表名
Delete/Truncate/Clear
使用代码
数据库上下文
删除
Truncate
清除
限制
参考
背景有时我们可能需要使用Entity Framework Core从表中删除所有记录。一种常用的方法是迭代每一行并使用DBSet.Remove()。
foreach (var item in Db.Users)
{
Db.Users.Remove(item);
}
Db.SaveChanges();
在这篇文章中,我们将探索一些替代方案。
扩展助手 先决条件需要安装NuGet包 Microsoft.EntityFrameworkCore.Relational
install Microsoft.EntityFrameworkCore.Relational
获取映射实体的表名和模式的扩展方法。我们将使用这个名称和模式来创建一个Truncate/Delete脚本。
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
public class AnnotationHelper
{
private static string GetName(IEntityType entityType, string defaultSchemaName = "dbo")
{
/*3.0.1 these were working*/
//var schemaName = entityType.GetSchema();
//var tableName = entityType.GetTableName();
var schema = entityType.FindAnnotation("Relational:Schema").Value;
string tableName = entityType.GetAnnotation("Relational:TableName").Value.ToString();
string schemaName = schema == null ? defaultSchemaName : schema.ToString();
string name = string.Format("[{0}].[{1}]", schemaName, tableName);
return name;
}
public static string TableName(DbContext dbContext) where T : class
{
var entityType = dbContext.Model.FindEntityType(typeof(T));
return GetName(entityType);
}
public static string TableName(DbSet dbSet) where T : class
{
var entityType = dbSet.EntityType;
return GetName(entityType);
}
}
有 DbSet 对象的扩展方法
- string Truncate(this DbSet dbSet)使用截断查询截断表
- string Delete(this DbSet dbSet)使用删除查询删除表的所有行
- void Clear(this DbSet dbSet)使用RemoveRange方法删除表的所有行
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using System.Data;
using System.Linq;
public static class EfHelper
{
public static string Truncate(this DbSet dbSet) where T : class
{
string cmd = $"TRUNCATE TABLE {AnnotationHelper.TableName(dbSet)}";
var context = dbSet.GetService().Context;
context.Database.ExecuteSqlRaw(cmd);
return cmd;
}
public static string Delete(this DbSet dbSet) where T : class
{
string cmd = $"DELETE FROM {AnnotationHelper.TableName(dbSet)}";
var context = dbSet.GetService().Context;
context.Database.ExecuteSqlRaw(cmd);
return cmd;
}
public static void Clear(this DbSet dbSet) where T : class
{
if (dbSet.Any())
{
dbSet.RemoveRange(dbSet.ToList());
}
}
}
我们当前的数据库上下文类。
public class AppDbContext : DbContext
{
public DbSet Users { get; set; }
}
Db.Users.Delete();
与数据库事务一起使用
string errorMsg = "Error";
User newUser = null;
Exception exception = null;
using (var tran = Db.Database.BeginTransaction())
{
try
{
newUser = new User()
{
Name = "Name",
Email = "Email",
CreatedBy = "CreatedBy",
CreatedOn = DateTime.Now
};
Db.Users.Add(newUser);
Db.SaveChanges();
Db.Users.Delete();
throw new Exception(errorMsg);
tran.Commit();
}
catch (Exception ex)
{
exception = ex;
tran.Rollback();
}
}
Db.Users.Truncate();
Db.Users.Clear();
Db.SaveChanges();
- Delete()和Truncate() SQL语句立即执行,不管我们是否调用Db.SaveChanges()
- 我们将无法进行单元测试Delete()和 Truncate()。
- Clear()对于大型数据集来说速度很慢,但可以进行单元测试。
- 使用SQL Server、Oracle测试的代码。
- 获取表名: https ://stackoverflow.com/questions/45667126/how-to-get-table-name-of-mapped-entity-in-entity-framework-core
https://www.codeproject.com/Tips/5320939/Delete-All-Rows-in-a-Table-in-Entity-Framework-Cor