|
■No90111 (レイ さん) に返信
ご参考に検証に使ったコードをアップしておきます。
コメントの「// 質問者さんのコードのように DataTable 経由で取得してみる」以降を追加して
います。読んでもらえば上で説明したことが分かりやすいと思います。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
using System.Data;
using System.Data.SqlClient;
namespace ConsoleAppJoinByLinq
{
class Program
{
static void Main(string[] args)
{
NORTHWINDEntities context = new NORTHWINDEntities();
// これは Linq to Entities
var delivery = from d in context.Order_Details
group d by d.ProductID into g
orderby g.Key
select new
{
ItemCode = g.Key,
Count = g.Sum(x => x.Quantity),
SumAmount = g.Sum(x => x.UnitPrice * x.Quantity)
};
// これも Linq to Entities
var test = from p in context.Products
join d in delivery
on p.ProductID equals d.ItemCode into dGroup
from item in dGroup.DefaultIfEmpty()
select new
{
ItemCode = p.ProductID,
Name = p.ProductName,
Count = item.Count,
SumAmount = item.SumAmount
};
// delivery を含めた test のコード全体を Linq to Entities として SQL に変換することができ、
// foreach で DB に SQL を投げることができ るので問題ない。
foreach (var x in test)
{
Console.WriteLine($"ID: {x.ItemCode}, Name: {x.Name}, Count: {x.Count}, Sum: {x.SumAmount}");
}
// 質問者さんのコードのように DataTable 経由で取得してみる
string connString = @"data source=lpc:(local)\sqlexpress;initial catalog=NORTHWIND;integrated security=True;";
string selectquery = "SELECT [OrderID],[ProductID],[UnitPrice],[Quantity],[Discount] FROM [Order Details]";
DataTable table = new DataTable();
using (SqlConnection connection = new SqlConnection(connString))
{
using (SqlCommand command = new SqlCommand(selectquery, connection))
{
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(table);
}
}
// これは Linq to Object
var delivery2 = from d in table.AsEnumerable()
group d by d.Field<int>("ProductID") into g
orderby g.Key
select new
{
ItemCode = g.Key,
Count = g.Sum(x => x.Field<Int16>("Quantity")),
SumAmount = g.Sum(x => x.Field<decimal>("UnitPrice") * x.Field<Int16>("Quantity"))
};
// delivery2 は Linq to Enitities ではない匿名型のオブジェクトのコレクション。
// それを上のような Linq to Entities のクエリに組み込むと SQL に変換できないということで以下のエラーになる。
// System.NotSupportedException: Unable to create a constant value of type 'Anonymous type'.
// Only primitive types or enumeration types are supported in this context.
// 可決策は以下のように両方 Linq to Object とすること。
var products = context.Products.ToList();
var test2 = from p in products
join d in delivery2
on p.ProductID equals d.ItemCode into dGroup
from item in dGroup.DefaultIfEmpty()
select new
{
ItemCode = p.ProductID,
Name = p.ProductName,
Count = item.Count,
SumAmount = item.SumAmount
};
foreach (var x in test2)
{
Console.WriteLine($"ID: {x.ItemCode}, Name: {x.Name}, Count: {x.Count}, Sum: {x.SumAmount}");
}
}
}
}
結果はいずれも以下の通りとなります。
ID: 1, Name: Chai, Count: 828, Sum: 14277.6000
ID: 2, Name: Chang, Count: 1057, Sum: 18559.2000
ID: 3, Name: Aniseed Syrup, Count: 328, Sum: 3080.0000
・・・中略・・・
ID: 77, Name: Original Frankfurter grune Sose, Count: 791, Sum: 9685.0000
|