Вам необходимо понять различия между IEnumerable
и IQueryable
.
Объект IEnumerable
содержит все для перечисления элементов в последовательности, которую представляет этот объект.Вы можете запросить первый элемент, и, получив его, вы можете многократно запрашивать следующий элемент, пока следующего элемента больше не будет.
IQueryable
работает по-другому.IQueryable
содержит Expression
и Provider
.Expression
- это общее описание того, какие данные следует выбрать.Provider
знает, кто должен выполнить запрос (обычно это база данных), и знает, как перевести Expression
в формат, понятный Provider
.
Существует два типа функций LINQ.: те, которые возвращают IQueryable<TResult>
и те, которые возвращают TResult
.Функции первого типа не выполняют запрос, они только меняют выражение.Они используют отложенное исполнение.Функции второй группы будут выполнять запрос.
Когда запрос должен быть выполнен, Provider
принимает Expression
и пытается преобразовать его в формат, понятный процессу, выполняющему запрос.Если этот процесс представляет собой систему управления реляционными базами данных, это обычно будет SQL.
Этот перевод является причиной того, что вы не можете добавить свою собственную функциональность: Expression
должен быть переведен в SQL, и единственноечто ваши функции могут делать - это вызывать функции, которые заменят Expression
на что-то, что может быть переведено в SQL.
На самом деле, даже структура сущностей не поддерживает все функции LINQ.Существует список поддерживаемых и неподдерживаемых методов LINQ
Вернуться к вашим вопросам
Могу ли я получить GetDeductibles непосредственно в моем запросе?
Нет, вы не можете, если вы не можете сделать это таким простым, что он изменит только Expression
, используя только методы поддержки LINQ.Вы должны будете написать это в формате функции расширения.См. Расширение методов расширения:
Ваш GetDeductibles должен иметь IQueryable<TSource>
в качестве ввода и возвращать IQueryable<TResult>
в качестве вывода:
static class QueryableExtensions
{
public static IQueryable<TResult> ToDeductibles<TSource, TResult, ...>(
this IQueryable<TSource> source,
... other input parameters, keySelectors, resultSelectors, etc)
{
IQueryable<TResult> result = source... // use only supported LINQ methods
return result;
}
}
Если вам действительно нужновызовите другие локальные функции, рассмотрите возможность вызова AsEnumerable
непосредственно перед вызовом локальных функций.Преимущество над ToList
состоит в том, что умные IQueryable
провайдеры, такие как тот, что в Entity Framework, будут получать не все элементы, а элементы на страницу .Поэтому, если вам нужно всего несколько, вы не перенесете все данные в локальный процесс.Убедитесь, что вы отбрасываете все данные, которые вам больше не нужны, перед вызовом AsEnumerable, тем самым ограничивая количество транспортируемых данных.
Могу ли я каким-то образом добавить значение после того, как я сделал .Select ()
LINQ предназначен для запроса данных, а не для их изменения.Прежде чем вы сможете изменить данные, вам придется их материализовать, прежде чем изменять.В случае запроса к базе данных это означает, что у вас есть копия заархивированных данных, а не оригинал.Поэтому, если вы вносите изменения, вы изменяете копии, а не оригиналы.
При использовании структуры сущностей вам придется выбирать каждый элемент, который вы хотите обновить / удалить.Убедитесь, что вы не выбираете значения, но выбираете оригинальные элементы.
НЕ:
var schoolToUpdate = schoolDbContext.Schools.Where(schoolId = 10)
.Select(school = new
{
... // you get a copy of the values: fast, but not suitable for updates
})
.FirstOrDefault();
НО:
School schoolToUpdate = schoolDbContext.Schools.Where(schoolId = 10)
.FirstOrDefault()
Теперь ваш DbContext имеет исходную школу вего ChangeTracker.Если вы измените SchoolToUpdate и вызовете SaveChanges, ваш SchoolToUpdate сравнивается с исходной школой, чтобы проверить, нужно ли обновлять школу.
Если вы хотите, вы можете обойти этот механизм, напрямую подключив новую школу.в ChangeTracker или вызов хранимой процедуры.