Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架已删除或已禁用列_C#_Sql Server_Entity Framework - Fatal编程技术网

C# 实体框架已删除或已禁用列

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子句充当其过滤器。然后

我从不想从一些表中删除行,所以我添加了一个IsDeleted列

表示这些表的POC都实现了iDeletable接口

当我做类似于-

context.Users.Where(u => u.Firstname == "Dave")
我只想返回没有设置IsDeleted位的行

我不想将
&&IsDeleted==false
添加到
的Where

我还希望此解决方案适用于
单个
第一个
,或仅适用于
上下文。用户
,等等


我希望有类似的解决方案。

您可以为每个表创建一个视图,其中where子句充当其过滤器。然后,您可以从实体框架而不是底层表访问该视图,而不用担心它。用户永远不知道底层表,只知道视图

根据trailmax下面的评论,是的,下面的原始答案确实将所有数据加载到内存中,因为它公开了链式枚举

尝试将
IQueryable
调用链接在一起时会出现两个问题

  • EF不知道如何翻译生成的
    .Invoke()
    调用
  • 如果您试图维护像
    .Where()
    这样的命名约定,那么最终会选择错误的扩展名,因为
    IDeletable
    只公开一个可以在其上构建谓词的列
  • 以下内容依赖于LinqKit库来链接表达式,语法不再流畅,但它确实避免了任何立即执行

    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));
        }
    }