在 EF Core 中设置预定义条件
Set predefined condition in 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
此代码是完美的 return 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();
这段代码是完美的 return 只有那些满足条件 isdeleted = false
.
的行
这很糟糕,因为它首先从数据库加载所有行,然后过滤/删除具有 isdeleted = true
值的行。
如果 table1 有 1M 行和 300K 行 isdeleted = true
那么它需要额外的时间和内存。
抱歉语法错误。
谢谢。
与其先获取整个列表,不如先使用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
我对 EF Core 不太熟悉,但如果它以与 EF6 类似的方式工作,那么当您在 DbSet 上调用 .ToList() 时,它将有效地执行相当于 SQL Select * 在 table/entity.
所以通过
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" 属性,则可以删除检查它是否存在的检查。代码尚未经过测试,但应该是正确的。
这段代码是从@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://whosebug.com/users/10070561/peterg
假设
// 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
此代码是完美的 return 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();
这段代码是完美的 return 只有那些满足条件 isdeleted = false
.
这很糟糕,因为它首先从数据库加载所有行,然后过滤/删除具有 isdeleted = true
值的行。
如果 table1 有 1M 行和 300K 行 isdeleted = true
那么它需要额外的时间和内存。
抱歉语法错误。
谢谢。
与其先获取整个列表,不如先使用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
我对 EF Core 不太熟悉,但如果它以与 EF6 类似的方式工作,那么当您在 DbSet 上调用 .ToList() 时,它将有效地执行相当于 SQL Select * 在 table/entity.
所以通过
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" 属性,则可以删除检查它是否存在的检查。代码尚未经过测试,但应该是正确的。
这段代码是从@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://whosebug.com/users/10070561/peterg