@lucky4

Как написать собственный расширяющий метод linq для сущности?

Хочу сделать пагинацию, сортировку и фильтрацию. Я до этого оказывается делал не правильно, я просто вытаскивал все данные из бд, и только потом применял фильры.. Что конечно же, не есть хорошо.
Теперь я додумался, но не пойму как такое можно реализовать...

Я сделал только пагинацию, и сюда я подумал что было бы хорошо запрокинуть типу функцию, которая будет принимать параметры типу => (int offset, int limit, string sortBy, string filter). Пока что только так:
public async Task<IList<TEntity>> GetAllPaged(int offset, int limit)
        {
            return await _context.Set<TEntity>()
                .Skip(offset)
                .Take(limit)
                .ToListAsync();
        }


Теперь вопрос, как сделать расширяющий метод для _context.Set? Должен ли быть это IEnumberable или же Queryable?
Вот что я попробовал сделать в этом абстрактном класс:
public static IEnumerable<TEntity> ApplyFiltEntity(this IEnumerable<TEntity> entity,
        Func<TEntity, string> field, string filter)
    {
        return entity.Where(x => field(x).Contains(filter));
    }


Но я не пойму куда его запихнуть) Если впихнуть его в этот класс, где находится работа с entity, то ошибку получаю, что расширяющие методы должны быть в non-generic-классах...
  • Вопрос задан
  • 182 просмотра
Решения вопроса 3
@dmitryKovalskiy
программист средней руки
1) Методы расширения должны быть расположены в сторонних static-классах. Создаем класс static SomeEntityMethodExtensions и внутри пишем что угодно.
2) Используйте IQueryable. C IEnumerable получите туже проблему что у вас и была - выгрузите все на сервер и будете крутить данные в пустую.

public static IQueryable<TEntity> ApplyFiltEntity(this IQueryable<TEntity> entity,
        Func<TEntity, string> field, string filter)
    {
        return entity.Where(x => field(x).Contains(filter));
    }
</code >
Однако скорее всего у вас будут проблемы с трансляцией переданной функции. Преобразовать ее в SQL 99% не выйдет
Ответ написан
vabka
@vabka Куратор тега C#
Токсичный шарпист
На сколько я понял, вам нужно что-то типа
public static QueryableExtensions {
    public static IQueryable<T> TakePaged<T>(this IQueryable<T> query, int take, int skip) =>
      query.Take(take).Skip(skip);
}

С сортировкой и фильтрацией уже сложнее - нужно в рантайме комбинировать деревья выражений.
Читайте: https://docs.microsoft.com/en-us/dotnet/csharp/pro...


Но я не пойму куда его запихнуть) Если впихнуть его в этот класс, где находится работа с entity, то ошибку получаю, что расширяющие методы должны быть в non-generic-классах...

Пихать нужно в отдельный класс. А метода вашего должен быть свой generic-параметр
https://docs.microsoft.com/en-us/dotnet/csharp/pro...
Ответ написан
@Dmitriyq
Дополню ответы методом сортировки по названию свойства
public static IOrderedQueryable<TSource> OrderByAscOrDesc<TSource>(this IQueryable<TSource> query, string propName, bool isDesc)
{
	var entityType = typeof(TSource);
	var propInfo = entityType.GetProperty(propName);
	if (propInfo.DeclaringType != entityType)
		propInfo = propInfo.DeclaringType.GetProperty(propName);

	if (propInfo == null) return (IOrderedQueryable<TSource>)query;

	var arg = Expression.Parameter(entityType, "x");
	var property = Expression.MakeMemberAccess(arg, propInfo);
	var selector = Expression.Lambda(property, new ParameterExpression[] { arg });

	var methodName = isDesc ? "OrderByDescending" : "OrderBy";
	var method = typeof(Queryable).GetMethods()
		.Where(x => x.Name == methodName && x.IsGenericMethodDefinition)
		.Where(x => x.GetParameters().Length == 2)
		.Single();

	var genericMethod = method.MakeGenericMethod(entityType, propInfo.PropertyType);
	return (IOrderedQueryable<TSource>)genericMethod.Invoke(genericMethod, new object[] { query, selector });
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы