首页 > 解决方案 > 在 EF Core 中设置预定义条件

问题描述

认为

// 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那么它需要额外的时间和内存。

抱歉语法不好。

谢谢你。

标签: c#sql-serverasp.net-core.net-coreef-core-3.0

解决方案


我对 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”属性,则可以删除检查它是否存在。代码尚未经过测试,但应该是正确的。


推荐阅读