Подтвердить что ты не робот

Создание кортежа в Linq Select

Я работаю с С# и .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 поддерживаются только конструкторы без параметров и инициализаторы к объектам.

Я не знаю, как мне создать Tuple, потому что все примеры, которые я нашел, в основном похожи на этот.

Я пробовал это:

codes = codesRepo.SearchFor(predicate)
      .Select(c => Tuple.Create(c.Id, c.Flag))
      .ToList();

И получите эту ошибку:

LINQ to Entities не распознает метод "System.Tuple`2 [System.String, System.Byte] Создайте метод [String, Byte] (System.String, Byte) и этот метод не может быть переведено в выражение хранилища.

Где проблема?

4b9b3361

Ответ 1

Хотя ответ от 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).

Ответ 2

Просто обновленный ответ для С# 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 })
.AsEnumerable()
.Select(c => (Id: c.Id, Flag: c.Flag))
.ToList();

Таким образом, вместо того, чтобы использовать его как Item1 или Item2, вы можете использовать его как Id или Flag.

Ответ 3

Попробуйте следующее:

codes = codesRepo.SearchFor(predicate)
  .Select(c => Tuple.Create(c.Id, c.Flag))
  .ToList();

Сообщено, что это не принимает в LINQ объектам.

Другой вариант - вывести результат в память перед выбором. Если вы собираетесь это сделать, я бы порекомендовал делать всю фильтрацию до .AsEnumerable(), поскольку это означает, что вы только отталкиваете результаты, которые хотите, а не оттягиваете всю таблицу и затем фильтруете.

codes = codesRepo.SearchFor(predicate).AsEnumerable()
  .Select(c => Tuple.Create(c.Id, c.Flag))
  .ToList();

а также Tuple.Create(c.Id, c.Flag) может быть изменен на новый Tuple (c.Id, c.Flag), если вы хотите сделать код более явным в типах кортежей

Ответ 4

В linq для сущностей вы можете проецировать анонимный тип или на DTO. Чтобы избежать этой проблемы, вы можете использовать метод расширения AsEnumerable:

codes = codesRepo.SearchFor(predicate).AsEnumerable().
      .Select(c => new Tuple<string, byte>(c.Id, c.Flag))
      .ToList();

Этот метод позволяет вам работать с Linq to Object вместо Linq для Entities, поэтому после его вызова вы можете проецировать результат запроса в то, что вам нужно. Преимущество использования AsEnumerable вместо ToList заключается в том, что AsEnumerable не выполняет запрос, он сохраняет отложенные выполнение. Хорошая идея всегда фильтровать ваши данные прежде, чем вызвать один из этих методов.

Ответ 5

Я нашел ответ:

codes = codesRepo.SearchFor(predicate)
      .ToList()
      .Select(c => Tuple.Create(c.Id, c.Flag))
      .ToList();

Ответ 6

Используйте этот метод, чтобы сделать это и использовать асинхронный.

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);

Ответ 7

Просто мои два цента: это меня несколько раз поймало с именами типов:

Несколько хороших примеров:

    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);
    }

С уважением.