C# 实体框架已删除或已禁用列
我从不想从一些表中删除行,所以我添加了一个IsDeleted列 表示这些表的POC都实现了iDeletable接口 当我做类似于-C# 实体框架已删除或已禁用列,c#,sql-server,entity-framework,C#,Sql Server,Entity Framework,我从不想从一些表中删除行,所以我添加了一个IsDeleted列 表示这些表的POC都实现了iDeletable接口 当我做类似于- context.Users.Where(u => u.Firstname == "Dave") 我只想返回没有设置IsDeleted位的行 我不想将&&IsDeleted==false添加到的Where 我还希望此解决方案适用于单个、第一个,或仅适用于上下文。用户,等等 我希望有类似的解决方案。您可以为每个表创建一个视图,其中where子句充当其过滤器。然后
context.Users.Where(u => u.Firstname == "Dave")
我只想返回没有设置IsDeleted位的行
我不想将&&IsDeleted==false
添加到的Where
我还希望此解决方案适用于单个
、第一个
,或仅适用于上下文。用户
,等等
我希望有类似的解决方案。您可以为每个表创建一个视图,其中where子句充当其过滤器。然后,您可以从实体框架而不是底层表访问该视图,而不用担心它。用户永远不知道底层表,只知道视图 根据trailmax下面的评论,是的,下面的原始答案确实将所有数据加载到内存中,因为它公开了链式枚举 尝试将
IQueryable
调用链接在一起时会出现两个问题
.Invoke()
调用.Where()
这样的命名约定,那么最终会选择错误的扩展名,因为IDeletable
只公开一个可以在其上构建谓词的列var users = context.Users.WhereIsNotDeleted(x => x.Id > 0).ToList();
public static class Extension
{
public static IEnumerable<T> WhereIsNotDeleted<T>(this IQueryable<T> source,
Expression<Func<T, bool>> predicate) where T : IDeletable
{
var query = source.AsExpandable().Where(x => !x.IsDeleted);
return query.Where(predicate);
}
}
在下面的简单测试中,只返回两条记录,因为第三条记录已被软删除
void Main()
{
var x = new List<Test>();
x.Add(new Test{ Number = "one" });
x.Add(new Test{ Number = "two" });
x.Add(new Test{ Number = "three", IsDeleted = true });
var y = x.WhereNotDeleted(a => a != null);
y.Count().Dump();
}
public class Test : IDeletable
{
public string Number { get; set; }
public bool IsDeleted { get; set; }
}
在这些扩展方法中,您必须通过实例调用而不是作为扩展方法来调用基本LINQ方法,否则将遇到堆栈溢出异常 我知道我没说,但我希望它不仅仅适用于某个地方。单身,第一或默认,等等都不能。它们是扩展方法,不能被重写,否则您将收到一个不明确的调用错误。每次我在EF旁边的LINQ中看到
IEnumerable
,我都会感觉到麻烦。我认为这可能会导致在内存中进行过滤,而不是在数据库中进行过滤。在大型电视台上,这可能对性能非常不利。虽然我还没有尝试/确认这一点,但这是需要注意的。只需运行一个小测试,我就可以确认这种过滤方式非常低效-EF确实从tableName
中选择*,然后在内存中进行过滤。这对于较小的数据集来说很好,但对于较大的数据集来说,性能和内存消耗非常糟糕。所以我不建议在生产系统中使用这种方法进行过滤。@trailmax您完全正确,我已经用一种有效的替代方法更新了我的答案。不幸的是,最初的答案是为了解决OP关于方便重用.Where()
的请求而创建的,但显然这会导致更大的问题。此项目可以帮助您:并且比公认的答案更有效。此处发布了一个更为防故障的解决方案:
void Main()
{
var x = new List<Test>();
x.Add(new Test{ Number = "one" });
x.Add(new Test{ Number = "two" });
x.Add(new Test{ Number = "three", IsDeleted = true });
var y = x.WhereNotDeleted(a => a != null);
y.Count().Dump();
}
public class Test : IDeletable
{
public string Number { get; set; }
public bool IsDeleted { get; set; }
}
public static class Extension
{
public static IEnumerable<IDeletable> Where(this IEnumerable<IDeletable> source,
Func<IDeletable, bool> predicate)
{
return System.Linq.Enumerable.Where(source, (x => predicate(x) && !x.IsDeleted));
}
}