在LINQ to Entities中只支持无参数的构造函数和初始值设定项
我在这个linqexpression式中有这个错误:
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();
任何想法如何解决这个问题? 我尝试用任何expression式的组合::/
没有关于“付款”的更多信息,这没有什么帮助,但是假设您想要创buildPayments对象并根据列值设置其某些属性:
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();
如果您仍然想使用您的构造函数来进行初始化而不是属性(有时这种行为是为了初始化目的而需要),通过调用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();
刚刚遇到这个错误,我想我会补充说,如果Payment
types是一个struct
,你也会遇到同样的错误,因为struct
types不支持无参数的构造函数。
在这种情况下,将Payment
转换为类并使用对象初始化程序语法将解决此问题。
如果你像我一样,不想为每个你正在构build的查询填充你的属性,还有另一种方法来解决这个问题。
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));
现在您的自定义对象(将两个对象作为参数)可以根据需要填充您的属性。
首先,我会避免与解决scheme
from .... select new Payments { Imie = nalTmp.Dziecko.Imie, .... }
这需要一个空的构造函数,并忽略封装,所以你说新的Payments()是没有任何数据的有效付款,而是对象必须至less有一个值,可能还有其他必需的字段,取决于你的域名。
有必要的领域的构造函数,但只带来需要的数据:
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();
对,像这样试试….
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();
这将使用无参数的构造函数重新创buildPayment对象,然后初始化大括号内所列的属性。 { }
你可以尝试做同样的事情,但使用扩展的方法。 数据库使用的提供者是什么?
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();
另外,如果你想使用一个具有多个对象的构造函数来初始化,如果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();
抱歉迟到了,但是我发现后,我认为这应该是共享的,因为它是我能find的最干净,最快和节省内存的实现。
根据你的例子,你会写:
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()使用的可能。
我今天遇到了同样的问题,我的解决scheme与Yoda列出的类似,不过它只能用stream利的语法。
使我的解决scheme适应您的代码:我将下面的静态方法添加到对象类
/// <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的解决scheme,其优点是将大量的成员初始化推送到类/数据传输对象
注意:最初我使用了更多的描述性名称,即“初始化程序”,但在回顾了我如何使用它之后,我发现“初始化程序”已经足够了(至less对于我的目的而言)。
最后注意:
在提出这个解决scheme之后,我原本以为分享相同的代码变得很简单,并且使其适用于查询语法。 我不再相信如此。 我认为,如果你想能够使用这种types的速记结构,你将需要一个方法,每个(查询,stream利)如上所述stream利,可以存在于对象类本身。
对于查询语法,将需要一个扩展方法(或正在使用的基类之外的某种方法)。 (因为查询语法想要操作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();
除了前面提到的方法外,还可以将其parsing为Enumerable集合,如下所示:
(from x in table .... ).AsEnumerable() .Select(x => ...)
当build立一个匿名对象时,这也有额外的好处,例如:
(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();
但是记住,将一个集合parsing为Enumerable会将其拉到内存中,因此可能会占用大量资源! 应该谨慎使用这里。