by WebSurfer
2018年4月30日 16:31
以下のコードを実行すると foreach (var item in list2) のところで System.NotSupportedException がスローされ、
1 つの LINQ to Entities クエリに含まれる構造的に互換性のない 2 つの初期化に、型 'ConsoleAppJoinByLinq2.JoinedList' が指定されています。1 つの型を同じクエリ内の 2 つの場所で初期化することはできますが、両方の場所で同じプロパティが同じ順序で設定されている必要があります。
・・・というエラーメッセージが表示されます。その理由と解決策を書きます。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleAppJoinByLinq2
{
public class JoinedList
{
public int ProductID { set; get; }
public string ProductName { get; set; }
public int CategoryID { get; set; }
public string CategoryName { set; get; }
}
class Program
{
static void Main(string[] args)
{
NORTHWINDEntities db = new NORTHWINDEntities();
var list1 = from c in db.Categories
where c.CategoryID == 1
select new JoinedList
{
CategoryID = c.CategoryID,
CategoryName = c.CategoryName
};
var list2 = from c in list1
join p in db.Products
on c.CategoryID equals p.CategoryID
select new JoinedList
{
ProductID = p.ProductID,
ProductName = p.ProductName,
CategoryName = c.CategoryName
};
foreach (var item in list2)
{
Console.WriteLine("{0}, {1}, {2}",
item.ProductID, item.ProductName, item.CategoryName);
}
}
}
}
上のコードでは、SQL Server のサンプルデータベース Northwind をベースに Visual Studio Communirt 2015 のウィザードを使って作った Entity Data Model (EDM) を使っています。以下の画像を見てください。
NORTHWINDEntities は EDM を作ると一緒に自動生成される DbContext クラスを継承したコンテキストクラスです。
Categories と Products は NORTHWINDEntities コンテキストクラスのプロパティで、データベースの当該テーブルを表すエンティティのコレクションを取得・設定するものです。
そして、肝心の話の何故エラーになるかの理由ですが、エラーメッセージの「両方の場所で同じプロパティが同じ順序で設定」という条件が満たされてない、即ち、list1 と list2 のクエリで JoinedList を初期化する際のプロパティの設定が異なるからです。
その前のエラーメッセージの条件「1 つの型を同じクエリ内の 2 つの場所で初期化」には該当しないように見えますが、list1 と list2 のクエリは両方 foreach のところで遅延評価されて、結局「同じクエリ内」ということになるようです。
解決策は、
-
list1 のクエリに ToList() を適用する(遅延評価されないように)、または、
-
JoinedList を初期化する際のプロパティの設定を、並び順序を含めて list1 / list2 のクエリで同じになるようにする
・・・です。そうすれば、以下の通り期待した結果が得られます。
9bdbf566-3a37-4e58-a35a-7d38e4f25d07|1|1.0
Tags: Linq
ADO.NET