Я работаю с C # и .NET Framework 4.5.1, получая данные из базы данных SQL Server с Entity Framework 6.1.3.
У меня есть это:
codes = codesRepo.SearchFor(predicate)
.Select(c => new Tuple<string, byte>(c.Id, c.Flag))
.ToList();
И когда я запускаю его, я получаю такое сообщение:
В LINQ to Entities поддерживаются только конструкторы и инициализаторы без параметров.
Я не знаю, как мне создать кортеж, потому что все примеры, которые я нашел, в основном похожи на этот.
Я пробовал это:
codes = codesRepo.SearchFor(predicate)
.Select(c => Tuple.Create(c.Id, c.Flag))
.ToList();
И получите эту ошибку:
LINQ to Entities не распознает метод 'System.Tuple`2 [System.String, System.Byte] Create [String, Byte] (System.String, Byte) », и этот метод нельзя преобразовать в выражение хранилища.
В чем проблема?
c#
entity-framework
linq
tuples
VansFannel
источник
источник
Ответы:
Хотя ответ по octavioccl работ, то лучше первого проект результата запроса в анонимный тип, а затем перейти к перечислимым и преобразовать его в кортеж. Таким образом, ваш запрос будет извлекать из базы данных только необходимые поля.
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) .AsEnumerable() .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
Примечание. Приведенное выше правило применяется к EF6. EF Core, естественно, поддерживает кортежи (в проекции или как ключи соединения / группы) через конструктор кортежей, например, исходный запрос просто работает
codes = codesRepo.SearchFor(predicate) .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
но не
Tuple.Create
метод (EF Core 2.x).источник
.Select(c => new { c.Id, c.Flag, c.Foo?.Code })
не работает.?.
не поддерживается в деревьях выражений. Но кроме этого, вы можете расширить анонимный тип,c => new { c.Id, c.Flag, Code = (int?)c.Foo.Code }
Просто обновленный ответ для C # 7, теперь вы можете использовать более простой синтаксис для создания ValueTuples.
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) .AsEnumerable() .Select(c => (c.Id, c.Flag)) .ToList();
Теперь вы даже можете назвать свойства кортежа:
codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) // anonymous type .AsEnumerable() .Select(c => (Id: c.Id, Flag: c.Flag)) // ValueTuple .ToList();
Поэтому вместо того, чтобы использовать его как Item1 или Item2, вы можете получить к нему доступ как Id или Flag.
Дополнительные документы по выбору между анонимным и кортежем
источник
Попробуй это:
Было сообщено, что это не принимается в LINQ to entity.
Другой вариант - вытащить результат в память перед выбором. Если вы собираетесь это сделать, я бы рекомендовал выполнить всю фильтрацию до .AsEnumerable (), поскольку это означает, что вы только отбираете те результаты, которые вам нужны, а не отбрасываете всю таблицу, а затем фильтруете.
также Tuple.Create (c.Id, c.Flag) можно изменить на новый Tuple (c.Id, c.Flag), если вы хотите сделать код более явным в типах кортежей
источник
В linq to entity вы можете проецировать на анонимный тип или на DTO. Чтобы избежать этой проблемы, вы можете использовать
AsEnumerable
метод расширения:codes = codesRepo.SearchFor(predicate).AsEnumerable(). .Select(c => new Tuple<string, byte>(c.Id, c.Flag)) .ToList();
Этот метод позволяет вам работать с Linq to Object вместо Linq to Entities , поэтому после его вызова вы можете проецировать результат своего запроса на все, что вам нужно. Преимущество использования
AsEnumerable
вместо этогоToList
заключается в том, чтоAsEnumerable
он не выполняет запрос, а сохраняет отложенное выполнение. Перед вызовом одного из этих методов рекомендуется всегда фильтровать данные.источник
Я нашел ответ:
источник
Используйте этот метод для этого и используйте файл async.
var codes = await codesRepo.SearchFor(predicate) .Select(s => new { Id = s.Id, Flag = s.Flag }).FirstOrDefaultAsync(); var return_Value = new Tuple<string, byte>(codes.Id, codes.Flag);
источник
Всего лишь два цента: несколько раз меня привлекали названия типов:
Несколько интересных примеров:
private Tuple<string, byte> v1() { return new Tuple<string, byte>("", 1); } private (string, int) v2() { return ("", 1); } private (string Id, byte Flag) v3() { return ("", 1); }
С уважением.
источник
public (string Id, byte Flag) SearchFor(Expression predicate)
, но это не к делу. Два цента должны быть не ответом, а комментарием.