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

时间:2010-08-25 23:43:55

标签: 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();

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

14 个答案:

答案 0 :(得分:114)

没有关于“付款”的更多信息,这没有多大帮助,但假设您要创建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();

答案 1 :(得分:107)

如果您仍想使用构造函数进行初始化而不是属性(有时需要此行为用于初始化),请通过调用ToList()ToArray()枚举查询,然后使用{{1 }}。因此,它将使用LINQ to Collections,并且无法使用Select(…)中的参数调用构造函数的限制将消失。

所以你的代码应该是这样的:

Select(…)

答案 2 :(得分:46)

我自己刚刚遇到此错误,我想我会补充一点,如果Payment类型是struct,您也会遇到相同的错误,因为struct类型不支持无参数构造

在这种情况下,将Payment转换为类并使用对象初始值设定语法将解决此问题。

答案 3 :(得分:17)

如果你像我一样,并且不想为你正在构建的每个查询填充你的属性,还有另一种方法可以解决这个问题。

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

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

答案 4 :(得分:8)

首先,我会避免使用

解决方案
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();

答案 5 :(得分:2)

您可以尝试执行相同操作,但使用扩展方法。数据库使用的提供者是什么?

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

答案 6 :(得分:2)

localhost/project/path/to/xampp/path/to/project/uploads/documents声明之前ToList()只需DbSet .. 实际的Select被保存为查询,但尚未完成。 在调用DbSet之后,您正在使用对象,然后您可以在查询中使用非默认构造函数。

不是最有效的使用时间方式,但它是小集合的选项。

答案 7 :(得分:1)

是的,试试这样......

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 :(得分:1)

除了上述方法之外,您还可以将其解析为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会将其拉入内存,因此可能会占用大量资源!这里应该谨慎使用。

答案 9 :(得分:1)

此外,如果要使用具有多个对象的构造函数进行初始化,如果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 :(得分:1)

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

根据你的例子,你写道:

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 :(得分:1)

我今天遇到了同样的问题,我的解决方案与Yoda列出的类似,但只能使用流利的语法。

使我的解决方案适应您的代码: 我将以下静态方法添加到对象类

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

然后将基本查询更新为以下内容:

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

这在逻辑上等同于James Manning的解决方案,其优点是可以将成员初始化的膨胀推向类/数据传输对象

注意:最初我使用的是更具描述性的名称&#34; Initializer&#34; 但在回顾我是如何使用它之后,我发现&#34; Initilizer&#34;足够了(至少对我而言)。

最后注意事项:
在提出这个解决方案之后,我原本以为共享相同的代码并使其适用于Query语法也很简单。我不再相信是这样的。我认为如果你想能够使用这种类型的速记构造,你需要一个方法,如上所述,每个(查询,流畅)流畅,可以存在于对象类本身。

对于查询语法,将需要扩展方法(或正在使用的基类之外的某些方法)。 (因为查询语法想要操作IQueryable而不是T)

以下是我用来最终使其用于查询语法的示例。 (尤达已经钉了这个,但我认为用法可能更清楚,因为我最初没有得到它)​​

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

和用法

{{1}}

答案 12 :(得分:0)

尽管回答晚了,它仍然可以帮助陷入困境的人。由于LINQ to实体不支持无参数对象构造。但是, IEnumerable 的投影方法。

因此,在选择之前,只需使用以下代码即可将 IQueryable 转换为 IEnumerable

var result = myContext.SomeModelClass.AsEnumerable().Select(m => m.ToString());

它将正常工作。但是,它当然会失去本机查询的好处。

答案 13 :(得分:0)

IQueryable<SqlResult> 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,
                          });
Repeater1.DataSource  = naleznosci.ToList(); 
Repeater1.DataBind();


public class SqlResult
{
        public string Imie { get; set; }
        public string Nazwisko { get; set; }
        ...
}