【问题标题】:Set predefined condition in EF Core在 EF Core 中设置预定义条件
【发布时间】:2020-08-16 04:39:06
【问题描述】:

假设

// connection strings and other configurations is not mentioned for simplicity
MyDbContext context = new MyDbContext();
Var Entities = Context.Set< table1>();
Var list = Entities.ToList();

LINQ to SQL 生成以下 SQL 查询:

Select col0, col1, isdeleted, coln  
From table1

这段代码很完美,返回了一个 table1 对象的列表(假设有 20 行)。

我的要求是:

// looking for a function or anything. This is my need
Entities.AddDefaultFilter("isdeleted", false);

// expected rows (18 rows, 2 rows have isdeleted = true) 
// Those should be excluded 
Var list = Entities.ToList();

我以非常糟糕的方式实现了这一点:

var list = Entities.ToList();

return list.Where(x => ((bool?)x.GetType().GetProperty("IsDeleted").GetValue(x)) == false).ToList(); 

这段代码很完美,只返回满足isdeleted = false条件的行。

这很糟糕,因为它首先从数据库中加载所有行,然后过滤/删除具有isdeleted = true 值的行。

如果 table1 有 1M 行和 300K 行,isdeleted = true 则需要额外的时间和内存。

抱歉语法错误。

谢谢。

【问题讨论】:

  • 我不能这样称呼:var list = Entities.Where(e=>e.IsDeleted==false).ToList();因为它是一个泛型存储库,泛型类型 T 没有属性 IsDeleted。

标签: c# sql-server asp.net-core .net-core ef-core-3.0


【解决方案1】:

我对 EF Core 不是很熟悉,但如果它以与 EF6 类似的方式工作,那么当您在 DbSet 上调用 .ToList() 时,它实际上会在表/实体上执行相当于 SQL Select * 的操作。

所以这样做

var list = Entities.ToList();

您正在将该实体的所有记录返回到内存中。然后过滤内存中的数据:

return list.Where(x => ((bool?)x.GetType().GetProperty("IsDeleted").GetValue(x)) == false).ToList();

如果您要执行以下操作:

return Entities.Where(x => !x.IsDeleted).ToList()

生成的 SQL 将包含 where 子句并且效率更高。

2020 年 4 月 5 日更新:

要包含泛型类型的过滤器,您可以构建一个表达式并将其传递给 LINQ 语句:

var props = typeof(TEntity).GetProperties();

if (props.Any(p => p.Name == "IsDeleted"))
{
    ParameterExpression pe = Expression.Parameter(typeof(TEntity), "x");

    ConstantExpression valExpression = Expression.Constant(true, typeof(bool));
    MemberExpression member = Expression.Property(pe, "IsDeleted");
    Expression predicateBody = Expression.Equal(member, valExpression);

    var final = Expression.Lambda<Func<TEntity, bool>>(body: predicateBody, parameters: pe);

    return Entities.Where(final.Compile()).ToList();
}
else
{
   return Entities.ToList();
}

如果您的所有实体都包含“IsDeleted”属性,则可以删除检查它是否存在。代码尚未经过测试,但应该是正确的。

【讨论】:

  • return Entities.Where(x => !x.IsDeleted).ToList() 这里x是泛型类型,所以x.Isdeleted无法识别。
  • 嗨@Iqbal,请查看编辑后的答案 - 我以为您只是想解决多次调用数据库的问题。
  • 你的代码很棒。它对我来说非常有用,但需要重新排列代码。只是将 pe 变量移到上面。
【解决方案2】:

不是先获取整个列表,你能不能在去服务器之前使用 where 谓词来过滤结果:

return Entities.Where(x => x.IsDeleted==false).ToList();

甚至更简单:

return Entities.Where(x => !x.IsDeleted).ToList();

这里的重点是语句末尾的 ToList()。然后它应该按如下方式输出 SQL:

Select col0,col1, isdeleted, coln from table1 WHERE isdeleted=0

【讨论】:

  • return Entities.Where(x => !x.IsDeleted).ToList() 这里x是泛型类型,所以x.Isdeleted无法识别。
  • 在这种情况下,您可以执行原始 SQL 查询......所以......返回 Entities.FromSqlRaw('SELECT .....')
【解决方案3】:

此代码是从@PeterG 的代码中复制并进行了一些修改:

 var props = typeof(T).GetProperties();
                if (props.Any(p => p.Name == "IsDeleted"))
                {
                    ConstantExpression valExpression = Expression.Constant(false, typeof(bool));//true to false
                    ParameterExpression pe = Expression.Parameter(typeof(T), "x");//this line was moved
                    MemberExpression member = Expression.Property(pe, "IsDeleted");
                    Expression predicateBody = Expression.Equal(member, valExpression);
                    var final = Expression.Lambda<Func<T, bool>>(body: predicateBody, parameters: pe);                

                    //var iq =(IQueryable<T>) Entities.Where(final.Compile());
                    //var sql = EfExtensions.ToSql(iq);
                    var list2 = Entities.Where(final.Compile()).ToList();//this the main expectation.
                    return list2 ;
                }
                else
                {//I keep my old code  if i ever need.
                    var list= Entities.ToList();
                    return list.Where(x => ((bool?)x.GetType().GetProperty("IsDeleted").GetValue(x)) != true).ToList();
                }

所有功劳归于 PeterG。谢啦。 https://stackoverflow.com/users/10070561/peterg

【讨论】:

    猜你喜欢
    • 2017-07-16
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    • 2022-06-22
    相关资源
    最近更新 更多