私はこの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();
この問題を解決する方法はありますか?どんな表現の組み合わせでも試してみます...:/
「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();
プロパティではなく初期化にコンストラクタを使用する場合(初期化の目的でこの動作が必要な場合があります)、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
型がstruct
である場合、struct
型はパラメーターなしのコンストラクターをサポートしないため、同じエラーが発生することを追加すると思いました。
その場合、Payment
をクラスに変換し、オブジェクト初期化子構文を使用すると、問題が解決します。
あなたが私のような人で、作成しているクエリごとにプロパティを設定する必要がない場合は、この問題を解決する別の方法があります。
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));
これで、カスタムオブジェクト(パラメーターとして2つのオブジェクトを取る)が必要に応じてプロパティを設定できます。
最初に私は解決策を避けるでしょう
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();
同じことを試みることができますが、拡張の方法を使用します。データベースの使用プロバイダーは何ですか?
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();
DbSet
ステートメントの前のToList()
Select
..実際のDbSet
はクエリとして保存されますが、まだ実行されていません。 ToList()
を呼び出した後、オブジェクトで遊んでいるので、クエリでデフォルト以外のコンストラクタを使用できます。
使用時間に関しては最も効率的な方法ではありませんが、小さなセットのオプションです。
前述のメソッドに加えて、次のように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として解析するとメモリにプルされるため、リソースを大量に消費する可能性があることに注意してください!ここでは注意が必要です。
今日も同じ問題があり、私のソリューションはヨーダがリストしたものと似ていましたが、流な構文でしか動作しません。
ソリューションをコードに適合させる:オブジェクトクラスに次の静的メソッドを追加しました
/// <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());
これは、メンバー初期化の肥大化をクラス/データ転送オブジェクトにプッシュするという利点を持つジェームズマニングのソリューションと論理的に同等です。
注:もともと「イニシャライザー」よりもわかりやすい名前を使用していましたが、使用方法を確認した後、「少なくともイニシャライザー」で十分であることがわかりました。
最終ノート:
このソリューションを思いついた後、もともと同じコードを共有し、これをクエリ構文でも機能するように適応させるのは簡単だと考えていました。私はもはやそうではないと信じています。この種の省略表記を使用できるようにするには、オブジェクトクラス自体に存在できる上記の各(クエリ、流()流methodなメソッドが必要だと思います。
クエリ構文の場合、拡張メソッド(または使用されている基本クラス以外のメソッド)が必要になります。 (クエリ構文はTではなくIQueryableを操作するため)
これが最終的にクエリ構文で機能するようにするために使用したもののサンプルです。 (ヨーダはすでにこれを打ち込んでいますが、最初は手に入らなかったので使用法はより明確になると思います)
/// <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();
パーティーに遅れてすみませんが、 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()による使用が可能です。ええ、このようにしてみてください。
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オブジェクトが更新され、中括弧{ }
内にリストされているプロパティが初期化されます
また、複数のオブジェクトを持つコンストラクターを使用して初期化する場合、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();
答えるのは遅れていますが、それでも苦しんでいる人を助けることができます。エンティティへのLINQは、パラメーターなしのオブジェクト構築をサポートしていないためです。ただし、 IEnumerable。
したがって、選択する前に、 IQueryable に IEnumerable このコードを使用して:
var result = myContext.SomeModelClass.AsEnumerable().Select(m => m.ToString());
それは正常に動作します。ただし、当然、ネイティブクエリの利点は失われます。