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

В LINQ для Entities поддерживаются только конструкторы и инициализаторы без параметров

У меня есть эта ошибка в этом выражении linq:

var naleznosci = (from nalTmp in db.Naleznosci
                              where nalTmp.idDziecko == idDziec
                              select new Payments
                              (
                                  nalTmp.Dziecko.Imie,
                                  nalTmp.Dziecko.Nazwisko,
                                  nalTmp.Miesiace.Nazwa,
                                  nalTmp.Kwota,
                                  nalTmp.RodzajeOplat.NazwaRodzajuOplaty,
                                  nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
                                  nalTmp.DataRozliczenia,
                                  nalTmp.TerminPlatnosci
                              )).ToList();

Любая идея, как решить эту проблему? Я пытаюсь с любой комбинацией выражения...:/

4b9b3361

Ответ 1

без дополнительной информации о "Платежах" это не очень помогает, но при условии, что вы хотите создать объект "Платежи" и установить некоторые его свойства на основе значений столбцов:

var naleznosci = (from nalTmp in db.Naleznosci
                              where nalTmp.idDziecko == idDziec
                              select new Payments
                              {
                                  Imie = nalTmp.Dziecko.Imie,
                                  Nazwisko = nalTmp.Dziecko.Nazwisko,
                                  Nazwa= nalTmp.Miesiace.Nazwa,
                                  Kwota = nalTmp.Kwota,
                                  NazwaRodzajuOplaty = nalTmp.RodzajeOplat.NazwaRodzajuOplaty,
                                  NazwaTypuOplaty = nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
                                  DataRozliczenia = nalTmp.DataRozliczenia,
                                  TerminPlatnosci = nalTmp.TerminPlatnosci,
                              }).ToList();

Ответ 2

Если вы все еще хотите использовать свой конструктор для инициализации, а не для свойств (иногда это поведение желательно для целей инициализации), перечислите запрос, вызвав ToList() или ToArray(), а затем используйте Select(…). Таким образом, он будет использовать LINQ to Collections и что ограничение на невозможность вызова конструктора с параметрами в Select(…) исчезнет.

Итак, ваш код должен выглядеть примерно так:

var naleznosci = db.Naleznosci
                          .Where(nalTmp => nalTmp.idDziecko == idDziec)
                          .ToList() // Here comes transfer to LINQ to Collections.
                          .Select(nalImp => new Payments
                              (
                                  nalTmp.Dziecko.Imie,
                                  nalTmp.Dziecko.Nazwisko,
                                  nalTmp.Miesiace.Nazwa,
                                  nalTmp.Kwota,
                                  nalTmp.RodzajeOplat.NazwaRodzajuOplaty,
                                  nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
                                  nalTmp.DataRozliczenia,
                                  nalTmp.TerminPlatnosci
                              ))
                          .ToList();

Ответ 3

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

В этом случае преобразование Payment в класс и использование синтаксиса инициализатора объекта разрешит проблему.

Ответ 4

Если вы похожи на меня и не хотите заполнять свои свойства для каждого запроса, который вы строите, есть другой способ решить эту проблему.

var query = from orderDetail in context.OrderDetails
            join order in context.Orders on order.OrderId equals orderDetail.orderId
            select new { order, orderDetail };

В этот момент у вас есть IQueryable, содержащий анонимный объект. Если вы хотите заполнить свой пользовательский объект конструктором, вы можете просто сделать что-то вроде этого:

return query.ToList().Select(r => new OrderDetails(r.order, r.orderDetail));

Теперь ваш пользовательский объект (который принимает два объекта в качестве параметра) может заполнить ваши свойства по мере необходимости.

Ответ 5

Сначала я бы избегал решения с помощью

from ....
select new Payments
{
  Imie = nalTmp.Dziecko.Imie,
  ....
}

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

Лучше иметь конструктор для обязательных полей, но только принести необходимые данные:

from ....
select new
{
  Imie = nalTmp.Dziecko.Imie,
  Nazwisko = nalTmp.Dziecko.Nazwisko
  ....
}
.ToList() // Here comes transfer to LINQ to Collections.
.Select(nalImp => new Payments
 (
  nalTmp.Imie,//assume this is a required field
  ...........
  )
  {
     Nazwisko = nalTmp.Nazwisko //optional field
  })
.ToList();

Ответ 6

Просто ToList() DbSet перед оператором Select. Фактический DbSet сохраняется как запрос, но еще не выполнен. После вызова ToList() вы играете с объектами, а затем вы можете использовать конструктор не по умолчанию в запросе.

Не самый эффективный способ использования по времени, но это вариант для небольших наборов.

Ответ 7

yeh, попробуйте вот так....

var naleznosci = (from nalTmp in db.Naleznosci
                              where nalTmp.idDziecko == idDziec
                              select new Payments()
                              {
                                  Dziecko.Imie,
                                  Dziecko.Nazwisko,
                                  Miesiace.Nazwa,
                                  Kwota,
                                  RodzajeOplat.NazwaRodzajuOplaty,
                                  RodzajeOplat.TypyOplat.NazwaTypuOplaty,
                                  DataRozliczenia,
                                  TerminPlatnosci
                              }).ToList();

это приведет к обновлению вашего объекта Payment с помощью конструктора без параметров, а затем инициализирует свойства, которые перечислены внутри фигурных скобок { }

Ответ 8

Вы можете попытаться сделать то же самое, но используя методы расширения. Что использует поставщик базы данных?

var naleznosci = db.Naleznosci
                          .Where<TSource>(nalTmp => nalTmp.idDziecko == idDziec)
                          .Select<TSource, TResult>(
                             delegate(TSource nalTmp) { return new Payments
                             (
                                 nalTmp.Dziecko.Imie,
                                 nalTmp.Dziecko.Nazwisko,
                                 nalTmp.Miesiace.Nazwa,
                                 nalTmp.Kwota,
                                 nalTmp.RodzajeOplat.NazwaRodzajuOplaty,
                                 nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
                                 nalTmp.DataRozliczenia,
                                 nalTmp.TerminPlatnosci
                             ); })
                          .ToList();

Ответ 9

Кроме того, если вы хотите использовать конструктор с несколькими объектами для инициализации, вы можете получить ошибку, если Linq не вернет значения.

Итак, вы можете сделать что-то вроде этого:

(from x in table_1
   join y in table_2
   on x.id equals y.id
   select new {
   val1 = x,
   val2 = y
})
.DefaultIfEmpty()
.ToList()
.Select(a => new Val_Constructor(a.val1 != null ? a.val1 : new Val_1_Constructor(),
                            a.val2 != null ? a.val2 : new Val_2_Constructor()))
.ToList();

Ответ 10

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

Адаптированный к вашему примеру, вы должны написать:

public static IQueryable<Payments> ToPayments(this IQueryable<Naleznosci> source)
{
  Expression<Func<Naleznosci, Payments>> createPayments = naleznosci => new Payments
  {
    Imie = source.Dziecko.Imie,
    Nazwisko = source.Dziecko.Nazwisko,
    Nazwa= source.Miesiace.Nazwa,
    Kwota = source.Kwota,
    NazwaRodzajuOplaty = source.RodzajeOplat.NazwaRodzajuOplaty,
    NazwaTypuOplaty = source.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
    DataRozliczenia = source.DataRozliczenia,
    TerminPlatnosci = source.TerminPlatnosci,
  };

  return source.Select(createPayments);
}

Большие преимущества здесь (как отметил Damien Guard в комментариях по ссылке):

  • Защищает вас от использования шаблона инициализации в каждом случае.
  • Использование через var foo = createPayments(bar);, а также использование через myIQueryable.ToPayments() возможно.

Ответ 11

У меня была такая же проблема сегодня, и мое решение было похоже на то, что перечислял Йода, однако он работает только с плавным синтаксисом.

Адаптация моего решения к вашему коду: Я добавил следующий статический метод в класс объекта

    /// <summary>
    /// use this instead of a parameritized constructor when you need support
    /// for LINQ to entities (fluent syntax only)
    /// </summary>
    /// <returns></returns>
    public static Func<Naleznosci, Payments> Initializer()
    {
        return n => new Payments
        {
             Imie = n.Dziecko.Imie,
             Nazwisko = n.Dziecko.Nazwisko,
             Nazwa = n.Miesiace.Nazwa,
             Kwota = n.Kwota,
             NazwaRodzajuOplaty = n.RodzajeOplat.NazwaRodzajuOplaty,
             NazwaTypuOplaty = n.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
             DataRozliczenia = n.DataRozliczenia,
             TerminPlatnosc = n.TerminPlatnosci
        };
    }

а затем обновить базовый запрос до следующего:

var naleznosci = (from nalTmp in db.Naleznosci
    where nalTmp.idDziecko == idDziec
    select new Payments.Initializer());

Это логически эквивалентно решению Джеймса Мэннинга с тем преимуществом, что нажатие раздувания инициализации члена на объект класса/передачи данных

Примечание. Первоначально я использовал более описательные имена, которые "Инициализатор" но после изучения того, как я его использовал, я обнаружил, что "Initilizer" было достаточно (по крайней мере для моих целей).

Заключительное примечание:
После того как я придумал это решение, я изначально думал, что было бы просто использовать один и тот же код и адаптировать его для работы с синтаксисом Query. Я больше не верю, что это так. Я думаю, что если вы захотите использовать этот тип стенографической конструкции, вам понадобится метод для каждого (запроса, свободного), как описано выше, который может существовать в самом объектном классе.

Для синтаксиса запроса потребуется использовать метод расширения (или какой-либо метод вне базового класса). (поскольку синтаксис запроса хочет использовать IQueryable, а не T)

Вот пример того, что я использовал, чтобы наконец заставить это работать для синтаксиса запроса. (Йода уже прибил это, но я думаю, что использование может быть более четким, потому что я не получил его сначала)

/// <summary>
/// use this instead of a parameritized constructor when you need support
/// for LINQ to entities (query syntax only)
/// </summary>
/// <returns></returns>
public static IQueryable<Payments> Initializer(this IQueryable<Naleznosci> source)
{
    return source.Select(
        n => new Payments
        {
            Imie = n.Dziecko.Imie,
            Nazwisko = n.Dziecko.Nazwisko,
            Nazwa = n.Miesiace.Nazwa,
            Kwota = n.Kwota,
            NazwaRodzajuOplaty = n.RodzajeOplat.NazwaRodzajuOplaty,
            NazwaTypuOplaty = n.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
            DataRozliczenia = n.DataRozliczenia,
            TerminPlatnosc = n.TerminPlatnosci
    };
}

и использование

var naleznosci = (from nalTmp in db.Naleznosci
    where nalTmp.idDziecko == idDziec
    select nalTmp).Initializer().ToList();

Ответ 12

В дополнение к вышеупомянутым методам вы также можете проанализировать его как коллекцию Enumerable, например:

(from x in table
....
).AsEnumerable()
.Select(x => ...)

Это также имеет дополнительное преимущество облегчения жизни при создании анонимного объекта, например:

 (from x in tableName
select x.obj)
.Where(x => x.id != null)
.AsEnumerable()
.Select(x => new {
   objectOne = new ObjectName(x.property1, x.property2),
   parentObj = x
})
.ToList();

Помня, однако, что разбор коллекции как Enumerable вызывает ее в памяти, поэтому она может быть ресурсоемкой! Здесь следует соблюдать осторожность.