LINQ to Entities中仅支持无参数构造函数和初始值设定项

net*_*jor 124 c# linq-to-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();
Run Code Online (Sandbox Code Playgroud)

任何想法如何解决这个问题?我尝试任何表达式的组合......:/

Jam*_*ing 118

没有关于"付款"的更多信息,这没有多大帮助,但假设您要创建Payments对象并根据列值设置其某些属性:

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();
Run Code Online (Sandbox Code Playgroud)

  • 只是为了补充这个答案,你不能用Structs做这个,只有Classes - 带我一点来解决这个问题! (54认同)
  • 这很好用,不要忘记为类添加一个空构造函数. (9认同)
  • 是的,我认为Tony的答案比这个更好,因为它实际上解决了眼前的问题,而这个问题通过改变Payments类的性质并可能阻止它不可变来解决问题. (4认同)
  • 这看起来很难看。EF6 有更好的方法吗? (2认同)

Ton*_*ony 109

如果您仍想使用构造函数进行初始化而不是属性(有时需要此行为用于初始化),请通过调用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();
Run Code Online (Sandbox Code Playgroud)

  • 为了澄清为什么这样做,最初声明的代码的问题是实体框架试图将构造函数调用与LINQ查询的其余部分一起传递给SQL,当然,SQL无法进行构建复杂的物体!通过插入ToList()调用,您可以将枚举从尚未执行的SQL查询移动到内存中对象的具体列表,然后您可以以任何您喜欢的方式进行操作. (21认同)
  • 不要为此使用`ToX()`,使用`AsEnumerable()`. (18认同)
  • 请注意,这将在数据库级别选择*all*列,通常它只会选择所需的列 (15认同)
  • 不仅如此,你可能会有多个枚举.我不喜欢这个解决方案. (4认同)
  • .ToList() // 这里传输到 LINQ to Collections。是为我解决问题的线路。 (2认同)

Gen*_*e C 46

刚刚遇到这个错误,我想我会补充一点,如果Payment类型是a struct,你也会遇到同样的错误,因为struct类型不支持无参数构造函数.

在那种情况下,转换Payment为类并使用对象初始化程序语法将解决该问题.


Jus*_*son 19

如果您像我一样,并且不希望为您正在构建的每个查询填充属性,则还有另一种方法可以解决此问题.

var query = from orderDetail in context.OrderDetails
            join order in context.Orders on order.OrderId equals orderDetail.orderId
            select new { order, orderDetail };
Run Code Online (Sandbox Code Playgroud)

此时,您有一个包含匿名对象的IQueryable.如果要使用构造函数填充自定义对象,可以执行以下操作:

return query.ToList().Select(r => new OrderDetails(r.order, r.orderDetail));
Run Code Online (Sandbox Code Playgroud)

现在,您的自定义对象(将两个对象作为参数)可以根据需要填充您的属性.


eug*_*gen 8

首先,我会避免解决方案

from ....
select new Payments
{
  Imie = nalTmp.Dziecko.Imie,
  ....
}
Run Code Online (Sandbox Code Playgroud)

这需要一个空的构造函数并忽略封装,因此您说新的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();
Run Code Online (Sandbox Code Playgroud)


Yod*_*oda 5

抱歉迟到了,但在找到这个之后,我认为应该分享它,因为它是我能找到的最干净、最快且节省内存的实现。

根据您的示例,您可以编写:

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);
}
Run Code Online (Sandbox Code Playgroud)

这里的最大优点(正如达米恩·卫德在链接的评论中指出的那样)是:

  • 避免您在每次出现时都使用初始化模式。
  • 通过var foo = createPayments(bar);以及使用也是myIQueryable.ToPayments()可能的。