Единственный способ, без динамического построения запросов, состоит в жестком коде в каждой комбинации и выборе того, который вы хотите.
Если имя таблицы является параметром для хранимой процедуры, это может быть в IF-блоках. Но это неудобно.
Если поля из каждой таблицы одинаковы, вы можете объединить таблицы вместе и выбрать из них ...
CREATE VIEW myUnifiedStructure AS
SELECT 'Table1' AS tableName, * FROM Table1
UNION SELECT 'Table2' AS tableName, * FROM Table2
UNION SELECT 'Table3' AS tableName, * FROM Table3
-- etc
SELECT * FROM myUnifiedStructure WHERE tableName = 'Table1'
Если поля в каждой таблице различны, вас может интересовать только подмножество полей ...
CREATE VIEW myUnifiedStructure AS
SELECT 'Table1' AS tableName, field1 AS field1, field4 AS field2 FROM Table1
UNION SELECT 'Table2' AS tableName, field2 AS field1, field3 AS field2 FROM Table2
UNION SELECT 'Table3' AS tableName, field2 AS field1, field4 AS field2 FROM Table3
-- etc
Или вы можете передать NULL для полей, которые не существуют в исходной таблице ...
CREATE VIEW myUnifiedStructure AS
SELECT 'Table1' AS tableName, NULL AS field1, field2 AS field2 FROM Table1
UNION SELECT 'Table2' AS tableName, field1 AS field1, field2 AS field2 FROM Table2
UNION SELECT 'Table3' AS tableName, field1 AS field1, NULL AS field2 FROM Table3
-- etc
Entity Framework не знает, как перевести ваш метод. Вы должны использовать метод, который возвращает Expression<Func<TsrEvent,EventModel>>
, или свойство, которое его хранит.
public List<EventModel> GetEvents(bool showInactive, bool showPastEvents)
{
return eventRepository
.GetEvents(_customerId, showInactive, showPastEvents)
.Select(ConvertPocoToModelExpr)
.ToList();
}
private static Expression<Func<TsrEvent,EventModel>> ConvertPocoToModelExpr => (x)=>new EventModel()
{
Id = x.EventId,
Name = x.EventName,
Capacity = x.EventCapacity,
Active = x.EventActive
};
Вы должны знать о различиях между IEnumerable
и IQueryable
.
Объект IEnumerable
содержит все для перечисления в последовательности. Вы можете запросить первый элемент, и как только у вас появится элемент, вы можете запросить следующий, если есть следующий. IEnumerable
должен обрабатываться локально вашим процессом.
Перечисление на самом низком уровне выполняется путем запроса перечислителя и повторного вызова MoveNext до тех пор, пока вам больше не понадобятся элементы. Например:
IEnumerable<Student> students = ...
IEnumerator<Student> studentEnumerator = students.GetEnumerator();
while (studentEnumerator.MoveNext())
{
// there is still a Student to process:
Student student = studentEnumerator.Current;
ProcessStudent(student);
}
Вы можете сделать это явно, или неявно вызвать его, используя foreach
или одну из функций LINQ.
С другой стороны, IQueryable
предназначен для обработки другим процессом, обычно системой управления базами данных. IQueryable
содержит Expression
и Provider
. Expression
выражает запрос, который должен быть выполнен в некотором общем формате. Provider
знает, кто должен выполнять запрос (обычно это система управления базами данных), и язык, который использует этот процесс (обычно что-то вроде SQL).
Как только вы начинаете перечисление, вызывая GetEnumerator, Expression
отправляется Provider
, который пытается перевести Expression
в SQL и выполняет запрос. Извлеченные данные помещаются в перечислимую последовательность, и перечислитель возвращается.
Вернуться к вашему вопросу
Проблема в том, что SQL не знает ConvertPocoToModel
. Следовательно, ваш провайдер не может конвертировать Expression
. Компилятор не может обнаружить это, потому что он не знает, насколько умен ваш Provider
. Вот почему вы не получите эту ошибку, пока не позвоните GetEnumerator
, в вашем случае - ToList
.
Решение
Решение - создать функцию, которая изменит выражение. Самый простой способ - это функция расширения. См. Методы расширения демистифицированы . Таким образом, вы можете использовать его как любой другой метод LINQ:
public static IQueryable<EventModel> ToEventModels(this IQueryable<TsrEvent> tsrEvents)
{
return tsrEvent.Select(tsrEvent => new EventModel
{
Id = tsrEvent.EventId,
Name = tsrEvent.EventName,
Capacity = tsrEvent.EventCapacity,
Active = tsrEvent.EventActive
};
}
Обратите внимание, что я опускаю ()
в конструкторе: SQL не может вызывать конструкторы!
Использование: [1142 ]
var result = dbContext.TsrEvents
.Where(tsrEvent => tsrEvent.Active && tsrEvent.Date == Today)
.ToEventModels()
.GroupBy(...)
... etc
Или, если ваш GetEvents
возвращает IQueryable<TsrEvents>
return eventRepository.GetEvents(_customerId, showInactive, showPastEvents)
.ToEventModels();
Заключительное замечание
Лучше позволить вашим данным- Функции fetch возвращают IQueryable<...>
и IEnumerable<...>
как можно дольше. Пусть только конечный пользователь материализует запрос. Было бы напрасной тратой вычислительной мощности, если вы выполняете ToList()
, а ваш абонент хочет только FirstOrDefault()