在 LINQtoEntity 中只支持无参数构造函数和初始值设定项

在这个 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();

有什么办法解决这个问题吗? 我尝试用任何表达式的组合... :/

110590 次浏览

是啊,试试这样..。

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

这将使用一个无参数构造函数创建您的 Pay 对象,然后初始化大括号 { }中列出的属性

如果没有更多关于“ Payments”的信息,这没有多大帮助,但是假设你想创建一个 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();

您可以尝试这样做,但使用扩展的方法。数据库的提供者使用什么?

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

我自己刚刚遇到了这个错误,我想我应该补充一下,如果 Payment类型是 struct,您也会遇到同样的错误,因为 struct类型不支持无参数构造函数。

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

如果您仍然希望使用构造函数进行初始化,而不是属性(有时候这种行为是为了初始化目的所需要的) ,那么在某些时候您需要使用 LINQ to Collection,因为 LINQ to SQL 不知道如何将构造函数转换为 SQL 查询。您可以通过使用 AsEnumerable()来实现这一点。

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

var naleznosci =
db.Naleznosci
.Where(nalTmp => nalTmp.idDziecko == idDziec)
.Select(nalTmp => new
{
DzieckoImie = nalTmp.Dziecko.Imie,
DzieckoNazwisko = nalTmp.Dziecko.Nazwisko,
MiesiaceNazwa = nalTmp.Miesiace.Nazwa
Kwota = nalTmp.Kwota,
NazwaRodzajuOplaty = nalTmp.RodzajeOplat.NazwaRodzajuOplaty,
NazwaTypuOplaty = nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
DataRozliczenia = nalTmp.DataRozliczenia,
TerminPlatnosci = nalTmp.TerminPlatnosci
}) // Select necessary columns from DB into anonymous type.
.AsEnumerable() // Here comes transfer to LINQ to Collections.
.Select(nalImp => new Payments
(
nalTmp.DzieckoImie,
nalTmp.DzieckoNazwisko,
nalTmp.MiesiaceNazwa,
nalTmp.Kwota,
nalTmp.NazwaRodzajuOplaty,
nalTmp.NazwaTypuOplaty,
nalTmp.DataRozliczenia,
nalTmp.TerminPlatnosci
)) // Use constructor to create your models.
.ToList();

如果您像我一样,不希望为构建的每个查询填充属性,那么还有另一种方法来解决这个问题。

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

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

除了上述方法之外,还可以将其解析为枚举集合,如下所示:

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

但是,请记住,将集合解析为 Enumable 会将其拖入内存,因此它可能是资源密集型的!在这里要小心。

此外,如果您想使用具有多个对象的构造函数进行初始化,那么如果 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();

首先,我会避免使用

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

这需要一个空的构造函数,并且忽略了封装,所以您说 new 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();

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

根据你的例子,你会写道:

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()使用是可能的。

我今天遇到了同样的问题,我的解决方案与尤达列出的类似,但它只能用流畅的语法工作。

根据您的代码调整我的解决方案: 我将以下静态方法添加到对象类中

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

这在逻辑上等同于 James Manning 的解决方案,其优点是将大量的成员初始化推送到 Class/Data Transfer Object

注意: 最初我使用的是更具描述性的名称“ Initializer” 但是在回顾了我是如何使用它之后,我发现“ Initiizer”已经足够了(至少对于我的目的而言)。

最后提示:
在提出这个解决方案之后,我最初认为共享相同的代码并使其适用于 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();

只要在 Select语句之前使用 ToList(). . 就像这样:

myDbSet.Where(x => something that minimizes the number of items).ToList().Select(...)

实际的 DbSet还没有脱离数据库。 在调用 ToList()之后,您正在处理对象,然后您可以在查询中使用非默认构造函数。

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

虽然现在回答已经晚了,但它仍然可以帮助处于困境中的人。因为 LINQ to 实体不支持无参数的对象构造。然而,数不胜数的投影方法。

因此,在选择之前,只需使用以下代码将 我有疑问转换为 数不胜数:

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

它会工作得很好,但是,当然,它会失去本机查询的好处。

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