質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Entity Framework

Entity Frameworkは、.NET Framework 3.5より追加されたデータアクセス技術。正式名称は「ADO.NET Entity Framework」です。データベースエンジンに依存しておらず、データプロバイダの変更のみで様々なデータベースに対応できます。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

1736閲覧

GridViewへの表示 C# WPF Entity Framework

tappuri

総合スコア7

Entity Framework

Entity Frameworkは、.NET Framework 3.5より追加されたデータアクセス技術。正式名称は「ADO.NET Entity Framework」です。データベースエンジンに依存しておらず、データプロバイダの変更のみで様々なデータベースに対応できます。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

2クリップ

投稿2019/08/02 17:24

編集2019/08/03 07:22

前提・実現したいこと

C# Entiry FrameworkコードファーストでWPFアプリを作成しています。
DataGridにデータを表示する際、結合しているテーブルのデータがクラス名?で表示されます。
中身のデータが表示されるようにできませんか?

そもそもDBの設計時点、データの挿入時点でよくないところがあれば指摘してください。

発生している問題・エラーメッセージ

イメージ説明
イメージ説明

該当のソースコード

XAML

1<Window x:Class="WpfAppTest.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WpfAppTest" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="306.505" Width="408.546"> 9 <Grid> 10 <Button x:Name="btnSelect" Content="Select" HorizontalAlignment="Left" Margin="10,45,0,0" VerticalAlignment="Top" Width="75" Click="BtnSelect_Click"/> 11 <Button x:Name="btnInsert" Content="Insert" HorizontalAlignment="Left" Margin="90,45,0,0" VerticalAlignment="Top" Width="75" Click="BtnInsert_Click"/> 12 <DataGrid x:Name="dgv" HorizontalAlignment="Left" Height="186" Margin="10,70,0,0" VerticalAlignment="Top" Width="361"/> 13 14 </Grid> 15</Window>

C#

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Text; 5using System.Threading.Tasks; 6using System.Windows; 7using System.Windows.Controls; 8using System.Windows.Data; 9using System.Windows.Documents; 10using System.Windows.Input; 11using System.Windows.Media; 12using System.Windows.Media.Imaging; 13using System.Windows.Navigation; 14using System.Windows.Shapes; 15 16using System.Data.Entity; 17using System.ComponentModel.DataAnnotations; 18using System.ComponentModel.DataAnnotations.Schema; 19 20namespace WpfAppTest 21{ 22 public class Product 23 { 24 [Key] 25 public int ProductID { get; set; } 26 public string Name { get; set; } 27 public string Maker { get; set; } 28 public ProductCategory Category { get; set; } 29 } 30 31 public class ProductCategory 32 { 33 [Key] 34 public int CategoryID { get; set; } 35 public string CategoryName { get; set; } 36 } 37 public class StockContext : DbContext 38 { 39 public DbSet<Product> Products { get; set; } 40 public DbSet<ProductCategory> ProductCategories { get; set; } 41 } 42 43 public partial class MainWindow : Window 44 { 45 public MainWindow() 46 { 47 InitializeComponent(); 48 } 49 50 private void BtnSelect_Click(object sender, RoutedEventArgs e) 51 { 52 using (var context = new StockContext()) 53 { 54 var query = context.Products 55 .Include(a => a.Category) 56 .ToArray(); 57 58 dgv.ItemsSource = query; 59 } 60 } 61 62 private void BtnInsert_Click(object sender, RoutedEventArgs e) 63 { 64 using (var context = new StockContext()) 65 { 66 context.Products.Add(new Product 67 { 68 Name = "TestProduct", 69 Maker = "TestMaker", 70 Category = new ProductCategory { CategoryName = "TestCategory" } 71 }); 72 context.SaveChanges(); 73 } 74 } 75 } 76}

試したこと

下記サイトを参考に作成しています。
https://densan-labs.net/tech/codefirst/chapter4.html

補足情報(FW/ツールのバージョンなど)

Microsoft Visual Studio Community 2019
Entity Framework 6.2.0

8/3 16:10 追記

SurferOnWwwさんからご回答頂いた内容の通り、SelectedDataクラスを追加してBtnSelect_Clickの内容を修正したところ正常にDataGridへ値を読みだせました。

C#

1 public class SelectedData 2 { 3 public int ProductID { get; set; } 4 public string Name { get; set; } 5 public string Maker { set; get; } 6 public string CategoryName { set; get; } 7 }

C#

1 private void BtnSelect_Click(object sender, RoutedEventArgs e) 2 { 3 using (var context = new StockContext()) 4 { 5 var query = from p in context.Products.Include(a => a.Category) 6 select new SelectedData 7 { 8 ProductID = p.ProductID, 9 Name = p.Name, 10 Maker = p.Maker, 11 CategoryName = p.Category.CategoryName 12 }; 13 14 dgv.ItemsSource = query.ToArray(); 15 } 16 }

また、Entity Framework 6 Power Tools Community Editionによるグラフ化、DB生成のSQL文の確認ができました。
イメージ説明

SQL

1create table [dbo].[Products] ( 2 [ProductID] [int] not null identity, 3 [Name] [nvarchar](max) null, 4 [Maker] [nvarchar](max) null, 5 [Category_CategoryID] [int] null, 6 primary key ([ProductID]) 7); 8create table [dbo].[ProductCategories] ( 9 [CategoryID] [int] not null identity, 10 [CategoryName] [nvarchar](max) null, 11 primary key ([CategoryID]) 12); 13alter table [dbo].[Products] add constraint [Product_Category] foreign key ([Category_CategoryID]) references [dbo].[ProductCategories]([CategoryID]);

いつもSSMSのデザイナからテーブルへの変更を加えていたのでER図?やSQL文を見るのはほぼ初めてですが、私が見たところ想定通りのDBになっているように思います。

しかしまだ気になる部分があります。
1つ目はEntity Framework, コードファーストというかっこよさげなものを使っていながらInsertとSelectでクラスを使い分けないといけない事です。これは、public ProductCategory Category { get; set; }のような書き方をやめて[ForeignKey()]などで代用して設計しなおすことで解消できるのでしょうか?(そもそもデータベースファーストを使用しろという話なのでしょうか)

2つ目はInsertしたときの挙動です。先程、想定通りのDBになっていると言ったもののProductCategiesテーブルをSSMSから確認するとCategoryNameに重複した値が書き込まれてしまっています。Entity Frameworkが勝手に判断してくれるということは無く、SQL同様に親テーブルにデータを入れておき、子テーブルに書き込むときに親テーブルのIDを使用するしかないでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/08/02 22:25

一枚目の画像はなんですか? BtnInsert_Click の結果 LocalDB にデータベースとテーブルが生成され、それから画像のクエリでデータを取得した結果ですか?
退会済みユーザー

退会済みユーザー

2019/08/02 22:39

そうだとすると、BtnSelect_Click のクエリがダメということになるはずです。.Include したのは ProductCatrgory オブジェクトなので 2 枚目の画像にはそれが表示されているということでしょう。 表示したいのは ProductCategory.CategoryName だと思いますが、であればそれを取得しないと期待通りにはなりません。
退会済みユーザー

退会済みユーザー

2019/08/02 22:43

ナビゲーションプロパティに virtual を付与しないのは意図的ですか? であれば、.Include を使うのは何故ですか?
hihijiji

2019/08/03 02:10

Entiry Frameworkはバージョンによって動作が大きく異なるので、バージョンは明記してください。
tappuri

2019/08/03 04:45

SurferOnWwwさん コメントありがとうございます。 仰る通り1枚目の画像はBtnInsert_Clickを押した結果をSSMSから確認したものです。 外部結合で値「TestCategory」が取得できたのでこれをDateGridに表示できれば成功と思ったのです。 >表示したいのは ProductCategory.CategoryName だと思いますが、であればそれを取得しないと期待通りにはなりません。 Insertには成功したがSelectに失敗しているという認識でよろしいでしょうか? virtual、.includeに関しては遅延読み込みなどを理解せずに、とりあえず書き込めて読み込みたからOKという考えで進めていたため意識できていませんでした。.IncludeはSQLでいうLEFT JOINと同等の感覚で使用していました。 また、回答の方にも情報を頂きありがとうございます。 これから頂いた内容を試してみます。 hihijijiさん コメントありがとうございます。 Enriry Frameworkのバージョンは6.2.0です。
退会済みユーザー

退会済みユーザー

2019/08/03 07:55

> しかしまだ気になる部分があります その話は、元々のこのスレッドの主題とはズレてきますので、別に新しいスレッドを立てて質問するようにしてください。後で検索などでここを訪れた人にとっては、一つの主題に対する Q&A にとどめておくのが、ここのようなノウハウの蓄積も目的としているサイトとしてあるべき姿と思いますので。 ちょっとだけ書くと、そもそも Linq では SELECT しかできません。DB の編集を行うために Entity Framework 上で必要な操作は、対象となるレコードのエンティティオブジェクトの状態を、INSERT するなら Added、UPDATE するなら Modified、DEETE するなら Deleted としてマークし、DbContext.SaveChanges メソッドを適用する他ないです。(質問者さんのコードもそうしています) エンティティの状態の操作 https://docs.microsoft.com/ja-jp/ef/ef6/saving/change-tracking/entity-state 上記を読んでもまだ疑問があれば、別に新しいスレッドを立てて質問するようにしてください。このスレッドはクローズしてください。
guest

回答1

0

ベストアンサー

上の質問に対するコメントに書いたことですが、具体的な修正案も追加して回答欄に書いておきます。

まず、一枚目の画像は BtnInsert_Click の結果 LocalDB にデータベースとテーブルが生成され、それから画像のクエリでデータを取得した結果と理解します。

その理解が正しければ、BtnSelect_Click のクエリがダメということになるはずです。.Include したのは ProductCatrgory オブジェクトなので 2 枚目の画像にはそれが表示されているということでしょう。(例外が出ないのがちょっと不思議ですが)

表示したいのは ProductCategory.CategoryName だと思いますが、であればそれを取得しないと期待通りにはなりません。以下のようにしてみてください。

まず、クエリの結果を格納するため以下のようなクラスクラスとプロパティ定義を追加する。プロパティの型は想像で書いていますので、実際と違ったら直してください。

public class SelectedData { public int ProductID { get; set; } public string Name { get; set; } public string Maker { set; get; } public string CategoryName { set; get; } }

BtnSelect_Click メソッドのクエリ式は以下のようにする。

var query = from p in context.Products.Include(a => a.Category) select new SelectedData { ProductID = p.ProductID, Name = p.Name, Maker = p.Maker, CategoryName = p.Category.CategoryName };

お試しください。

ナビゲーションプロパティへの virtual を付与する件ですが、遅延ローディングが必要(普通は必要)なら virtual を付与する必要があります。

遅延ローディングされては無駄なクエリが複数回投げられるという場合、今回のケースのように .Include を使うということになります。

詳しくは以下の記事の "Learn how to load related data" を読んでください。

Tutorial: Read related data with EF in an ASP.NET MVC app
https://docs.microsoft.com/ja-jp/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/reading-related-data-with-the-entity-framework-in-an-asp-net-mvc-application

【追加情報】

今回の問題とは関係ないオマケ的な話ですが・・・

DB First で .edmx を作った時と同様に、Code First の DbContextから EDM をグラフィカルに表示するツールが利用できます。大変有用なので入手してインストールすることをお勧めします。

Entity Framework 6 Power Tools Community Edition
https://marketplace.visualstudio.com/items?itemName=ErikEJ.EntityFramework6PowerToolsCommunityEdition

イメージ説明

回答欄の「8/3 16:10 追記」の件

しかしまだ気になる部分があります

その話は、元々のこのスレッドの主題とはズレてきますので、別に新しいスレッドを立てて質問するようにしてください。後で検索などでここを訪れた人にとっては、一つの主題に対する Q&A にとどめておくのが、ここのようなノウハウの蓄積も目的としているサイトとしてあるべき姿と思いますので。

ちょっとだけ書くと、そもそも Linq では SELECT しかできません。DB の編集を行うために Entity Framework 上で必要な操作は、対象となるレコードのエンティティオブジェクトの状態を、INSERT するなら Added、UPDATE するなら Modified、DELETE するなら Deleted としてマークし、DbContext.SaveChanges メソッドを適用する他ないです。(質問者さんのコードもそうしています)

エンティティの状態の操作
https://docs.microsoft.com/ja-jp/ef/ef6/saving/change-tracking/entity-state

上記を読んでもまだ疑問があれば、別に新しいスレッドを立てて質問するようにしてください。このスレッドはクローズしてください。

投稿2019/08/03 02:30

編集2019/08/03 08:01
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tappuri

2019/08/03 08:58

更に回答ありがとうございます。 この質問はSurferOnWwwさんの回答をもって解決、クローズと致します。 LINQやその構文については別途質問する予定です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問