简体   繁体   English

在 EF Core 中设置预定义条件

[英]Set predefined condition in EF Core

Assume认为

// 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 generates the following SQL query: LINQ 到 SQL 生成以下 SQL 查询:

Select col0, col1, isdeleted, coln  
From table1

This code is perfect and return a list of table1 objects (suppose 20 rows).这段代码是完美的,并返回 table1 对象的列表(假设 20 行)。

My requirement is:我的要求是:

// 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();

I achieved this in a very poor way:我以非常糟糕的方式实现了这一点:

var list = Entities.ToList();

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

This code is perfect and return only those rows that meet the condition isdeleted = false .这段代码很完美,只返回那些满足条件isdeleted = false的行。

This is poor because first it loads all rows from the database, then filters / removes the rows which have isdeleted = true value.这很糟糕,因为它首先从数据库加载所有行,然后过滤/删除具有isdeleted = true值的行。

If table1 has 1M rows and 300K rows with isdeleted = true then it takes extra time and memory.如果 table1 有 1M 行和 300K 行且isdeleted = true则需要额外的时间和 memory。

Sorry for bad grammar.抱歉语法不好。

Thank you.谢谢你。

I'm not that familiar with EF Core but if it works in a similar way to EF6 then when you call.ToList() on a DbSet it will effectively do the equivalent of a SQL Select * on the table/entity.我对 EF Core 不太熟悉,但如果它以与 EF6 类似的方式工作,那么当您在 DbSet 上调用 .ToList() 时,它将有效地在表/实体上执行相当于 SQL Select * 的操作。

So by doing所以通过做

var list = Entities.ToList();

You are returning all records for that entity into memory.您将该实体的所有记录返回到 memory。 This then filters the in memory data:然后过滤 memory 数据:

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

If you were to do something like:如果您要执行以下操作:

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

The SQL generated would include the where clause and be much more efficient.生成的 SQL 将包含 where 子句并且效率更高。

Updated 04/05/2020: 2020 年 4 月 5 日更新:

To include a filter for a generic type you could build an expression and pass that into the LINQ statement:要包含泛型类型的过滤器,您可以构建一个表达式并将其传递到 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();
}

If all of your entities include the "IsDeleted" property then the check to see if it exists could be removed.如果您的所有实体都包含“IsDeleted”属性,则可以删除检查它是否存在。 Code hasn't been tested but should be along the right lines.代码尚未经过测试,但应该是正确的。

Instead of getting the entire list first, could you not use the where predicate to filter the results before going to the server:与其先获取整个列表,不如在访问服务器之前使用 where 谓词过滤结果:

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

or even simpler:甚至更简单:

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

The important point here is the ToList() at the end of the statement.这里的重点是语句末尾的 ToList()。 It should then output the SQL as follows:那么 output 和 SQL 应该如下:

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

This code is copied from @PeterG's code and bit modified:这段代码是从@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();
                }

All credit goes to PeterG.所有的功劳都归于 PeterG。 Thanks man.谢啦。 https://stackoverflow.com/users/10070561/peterg https://stackoverflow.com/users/10070561/peterg

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM