C# 删除实体而不在通用存储库模式实体框架中获取它
我正在尝试从数据库中删除Employee实体,该数据库包含不同的表,如Employee、Project和Skills,使用通用存储库模式C# 删除实体而不在通用存储库模式实体框架中获取它,c#,sql,entity-framework,generics,repository-pattern,C#,Sql,Entity Framework,Generics,Repository Pattern,我正在尝试从数据库中删除Employee实体,该数据库包含不同的表,如Employee、Project和Skills,使用通用存储库模式 namespace Information.Repository { public class IRepositoy<TEntity> : IRepository<TEntity> where TEntity : class { private readonly ApplicationDbContext
namespace Information.Repository
{
public class IRepositoy<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly ApplicationDbContext _dbContext;
public IRepositoy(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public void Remove(int id)
{
TEntity element = _dbContext.Set<TEntity>().Find(id);
_dbContext.Set<TEntity>().Remove(element);
}
}
}
有谁能建议我如何删除实体而不使用类似于上述示例的通用存储库模式获取它。您仍然需要获取它。实体框架缓存您的数据库集,所以它通常非常快。使用相同的上下文,如下所示:
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
其中dbSet=
context.Set<TEntity>();
context.Set();
实体框架的当前限制是,为了更新或删除实体,必须首先将其检索到内存中。但是,几乎没有其他方法可以删除特定记录
您可以尝试ExecuteSqlCommand
删除特定记录
_dbContext.Database.ExecuteSqlCommand("Delete Employee where EmployeeId = {0}", id );
_dbContext.Settings.Where(s=> s.EmployeeId == id).Delete();
或者尝试使用库删除特定记录
_dbContext.Database.ExecuteSqlCommand("Delete Employee where EmployeeId = {0}", id );
_dbContext.Settings.Where(s=> s.EmployeeId == id).Delete();
使用原始SQL
实体框架不允许删除尚未加载(或附加)的对象。这还扩展到条件删除(例如,删除所有名为John的用户),因为它要求您在删除用户之前加载这些用户
您可以通过执行原始SQL来解决这个问题。这并不理想,因为您倾向于使用EF,因此不必编写SQL,但由于缺乏良好的删除行为(不加载),因此这是一个可接受的解决方案
大致如下:
using (var context = new FooContext())
{
var command = "DELETE * FROM dbo.Foos WHERE Id = 1";
context
.Database
.ExecuteSqlCommand(command);
}
public class BaseEntity
{
public int Id { get; set; }
public DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public DateTime? UpdatedOn { get; set; }
public string UpdatedBy { get; set; }
}
在相关的地方,不要忘记SQL注入保护。但是,对于简单删除来说,这通常不是问题,因为FK通常是GUID或int,这不会使您受到注入攻击
使其通用 您发布的示例也可以使用,但您可能没有使用它,因为它不容易变得通用友好 在我的所有EF项目中,我倾向于为我的所有实体创建一个(抽象)基类,大致如下:
using (var context = new FooContext())
{
var command = "DELETE * FROM dbo.Foos WHERE Id = 1";
context
.Database
.ExecuteSqlCommand(command);
}
public class BaseEntity
{
public int Id { get; set; }
public DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public DateTime? UpdatedOn { get; set; }
public string UpdatedBy { get; set; }
}
接口也可以,我只是更喜欢基类
审计字段不是这个答案的一部分,但它们确实展示了拥有基类的好处
当所有实体从同一基类继承时,可以在存储库上设置泛型类型约束,以确保泛型类型具有Id
属性:
public class IRepositoy<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
还可以指定无参数构造函数类型约束:
where TEntity : BaseEntity, new()
这也使您能够实例化您的泛型类型:
public void Remove(int id)
{
TEntity obj = new TEntity() { Id = id };
dbContext.Entry(obj).State = EntityState.Deleted;
}
注意还有一个通用的原始SQL解决方案,但我省略了它,因为它更复杂,因为它要求您根据实体类型检索表名。
原始SQL变量仅在希望执行条件删除的情况下才有价值(例如,删除id为偶数的所有实体) 但是,由于大多数条件删除是特定于实体的,这意味着您通常不需要将它们设置为通用的,这使得原始SQL方法更加可行,因为您只需要在特定的存储库中实现它,而不需要在通用的存储库中实现它
如果您使用的是.Net Core,中介绍的软删除将对您有所帮助。请看一看解释的通用存储库的陷阱。请注意,链接库已4年不受支持,删除功能现在被锁定在付费许可证之后。这里它还向数据库发出两个调用,一个用于获取实体,另一个用于删除实体。当您执行我发布的第二个示例时,它将进行一次查询以删除实体。问题是:删除[dbo].[EmployeeId]=21)@Rana:这个答案并不是说只在一次呼叫中完成,而是告诉你EF打算如何使用它(实际上是两次呼叫,而不是一次)。@Rana:看我的答案。答案很好,有详细的解释,还提到了坑落。不相关,但我通常不鼓励使用具有丰富ORM(如EF/NH)的通用存储库。我已经讨论过了。