EntityFramework 上软删除的优雅方式是什么?我已将一个属性(数据库字段)标识为已删除,并始终在linq语句中使用此过滤器。
像
Foo Class
int NumberField
string Description
bool Deleted
contexts.Foos.Where(x=> !x.Deleted);
复杂查询不可行。
任何帮助表示赞赏..
答案 0 :(得分:2)
是的,这可以通过EF via pattern实现。 如果你使用Fascade / repository模式并通过该fascade访问每一次。
例如 所有存储库类上的接口实现可能如下所示:
class MyRepositoryBase<T>....
public IQueryable<T> ValidQuerySet // this is not deleted check Set
{ get { return Context.Set<T>().Where(t => t.deleted != true);
}
}
您将完全像访问原始DbSet一样进行访问。 EF将结合条件。
var myQuerySet = MyRespository<T>.ValidQuerySet.Where(t=>t.foo == "bar");
答案 1 :(得分:1)
您可能需要考虑在上下文类本身上创建存储库(如this site上所示),而不是直接查询您的上下文。您可以做的就是在查询记录时(例如,使用存储库的Filter<T>(Expression<Func<T, bool>> predicate)
方法,您可以始终执行以下操作:
return Context.Set<Foo>().Where<Foo>(x => !x.Deleted).Where<Foo>(predicate).AsQueryable<Foo>();
如果您要在多个对象类型中实现该软删除,然后将其拉入抽象类(例如,将其称为SoftDeleteable
),那么更好的是,然后使用Filter方法签名可以是:
public virtual IQueryable<T> Filter<T>(Expression<Func<T, bool>> predicate) where T : SoftDeletable
答案 2 :(得分:0)
你可能不会喜欢我的答案,但我能想到的“不那么痛苦”的方式需要大量的存储过程:每个实体1个,而你所做的只是存在UPDATE foo Deleted = True。我的通常看起来像这样
PROCEDURE [dbo].[SP_Address_UnSet]
@ID bigint
AS
BEGIN
DECLARE @IsInactive bit
SELECT @IsInactive = IsInactive
FROM [Address]
WHERE AddressID = @ID
IF (0 = @@ROWCOUNT)
RETURN -1
-- implicit else
IF (1 = @IsInactive)
RETURN 0
-- implicit else
UPDATE [Address]
SET IsInactive = 1
WHERE AddressID = @ID
RETURN @@ROWCOUNT -- should be 1
END
然后在该SP的每个实体地图上。
你可以拥有1个单独的SP,并将表名作为参数传递,但由于你不能通过动态查询直接在T-SQL中使用它,你必须构建子执行(并且担心avout SQL注入! !)
Exec('SELECT * FROM ' + @tableName)
答案 3 :(得分:0)
Global Query Filters (EF Core)和Entity Framework Interceptors (EF 6+)是EntityFramework上添加的新功能,用于解决此类问题。
答案 4 :(得分:-1)
我发现以这种方式进行“软删除”非常痛苦:
我建议您只需将“已删除”条目放入不同的表格或数据库中,从长远来看,这将节省您的时间。