Установить предопределенное условие в EF Core - PullRequest
0 голосов
/ 01 мая 2020

Предположим,

// 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, тогда это требует дополнительного времени и памяти.

Извините за плохую грамматику.

Спасибо.

Ответы [ 3 ]

1 голос
/ 01 мая 2020

Я не так хорошо знаком с EF Core, но если он работает аналогично EF6, то когда вы вызываете .ToList () для DbSet, он фактически делает эквивалент SQL Select * для таблицы / 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 и будет гораздо более эффективным.

Обновлено 04/05/2020:

Чтобы включить фильтр для обобщенного типа c, можно создать выражение и передать его в оператор 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, тогда проверка, чтобы проверить, существует ли она, может быть удалена. Код не был проверен, но должен быть в правильном направлении.

0 голосов
/ 05 мая 2020

Этот код скопирован из кода @ 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. Спасибо чувак. { ссылка }

0 голосов
/ 01 мая 2020

Вместо того, чтобы сначала получить весь список, не могли бы вы использовать предикат 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
...