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

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

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

DataSetは、ADO.NETアーキテクチャのコンポーネントです。データベースから取得したレコードをメモリ領域に格納するクラスを指します。データの保持やテーブル間のリレーション・制約といった保持も可能です。

Visual Studio 2010

Microsoft Visual Studio 2010はMicrosoftが提供している統合開発環境(IDE)です。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

Q&A

解決済

1回答

22592閲覧

DataTableを片側外部結合したい(Left Joinのような)

meesa

総合スコア12

DataSet

DataSetは、ADO.NETアーキテクチャのコンポーネントです。データベースから取得したレコードをメモリ領域に格納するクラスを指します。データの保持やテーブル間のリレーション・制約といった保持も可能です。

Visual Studio 2010

Microsoft Visual Studio 2010はMicrosoftが提供している統合開発環境(IDE)です。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

0グッド

0クリップ

投稿2017/11/24 03:13

###前提・実現したいこと
ASP.NetでWEB画面を開発しています。
データベースやCSVに出力されているデータを元にGridViewを作成し、
ひとつのテーブルを表示させる画面を開発中です。

データは複数に分かれており、PG内で情報を結合する必要があります。
テーブル1に表示されているすべての行に対し、
テーブル2のユーザーIDの一致する行の、システム利用権限の情報を表示しようとしています。

・テーブル1 ←Oracle DB
ユーザーID 部署 氏名
==============
ID0001 部署A 鈴木太郎
ID0002 部署A 山田一郎
ID0003 部署B 佐藤花子

・テーブル2 ←CSVファイル
ユーザーID システム利用権限
==============
ID0001 ○
ID0003 ×
ID0004 ○

テーブル1と2は、どちらか片方にしか情報のないユーザーの情報が含まれていますが、
上記のような場合、下記のようなデータを取り出したいです。

ユーザーID 部署 氏名 システム利用権限
=================
ID0001 部署A 鈴木太郎 ○
ID0002 部署A 山田一郎 Null
ID0003 部署B 佐藤花子 ×

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

下記の質問の回答を元に、Relationを作成しようとするのですが、
DataSet.Relations.Addでリレーションを追加するところでエラーとなってしまいます。
https://teratail.com/questions/65331

ArgumentExceptionはユーザーコードによってハンドルされませんでした:
対応する親の値が指定されてない値があるため、この制約を有効にできません。

###該当のソースコード

VB.NET

1'戻り値用 2Dim Kekka As New DataSet 3Dim FullUserList As New DataTable 4 5Dim UserInfoSet As New DataSet 6Dim Tb1List As New DataTable 7Dim Tb2List As New DataTable 8 9'テーブル1をUserInfoSetのDataTableに格納 10UserInfoSet = GetTb1List() 11Tb1List= UserInfoSet.Tables(TB_USRINFO) 12 13'テーブル2をUserInfoSetのDataTableに格納し、UserInfoSetに追加 14Tb2List = GetTb2List() 15UserInfoSet.Tables.Add(Tb2List) 16 17'リレーションを作成 18UserInfoSet.Relations.Add(New DataRelation("TEST", _ 19Tb1List .Columns("UserID"), _ 20Tb2List .Columns("UserID"))) 'ここでエラー発生 21 22'結合結果のDataTableの名前を定義 23FullUserList.TableName = TB_FULLUSERLIST 24 25'フル項目分のカラムを作成 26FullUserList.Columns.Add("USERID") 27FullUserList.Columns.Add("SECTNM") 28FullUserList.Columns.Add("USERNM") 29FullUserList.Columns.Add("Kengen") 30 31'テーブルに値を追加 32For Each r As DataRow In UserInfoList.Rows 33 34 Dim t2r As DataRow = r.GetParentRow("TEST") 35 FullUserList.Rows.Add(r.Item("USERID"), r.Item("SECTNM"), _ 36 r.Item("USERNM"), t2r.Item("Kengen")) 37 38Next 39 40'新規に作成したテーブルを返却用データセットに格納 41Kekka.Tables.Add(FullUserList)

###試したこと
Tb1ListとTb2Listには、それぞれ値がセットできていることは確認済みです。
それぞれ単独ではGridViewへバインドができ、表示結果もデータと一致しています。
なお、Tb2ListのCSVファイルは、Schema.iniファイルでカラム名と型を定義しています。

###補足情報(言語/FW/ツール等のバージョンなど)
ASP.Net (VB) .NetFramework4.0
Visual Studio 2010

どなたか回答、アドバイスなどお待ちしています。

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

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

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

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

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

guest

回答1

0

ベストアンサー

下記の質問の回答を元に、Relationを作成しようとするのですが

リレーションを張るのが目的ではなくて、「テーブル1」と「テーブル2」を左外部結合した結果を GridView に表示できれば良いということであれば・・・

DataSet / DataTable を作ってそれを操作しようとするより、以下のように List<T> 型として「テーブル1」と「テーブル2」のレコードを取得し、Linq を使って結合した方がよさそうです。

左外部結合の実行
https://docs.microsoft.com/ja-jp/dotnet/csharp/linq/perform-left-outer-joins

【追記】

上記案でのサンプルを書いておきます。Oracle の方は Entity Framework を使えれば簡単に、CSV の方も DataSet / DataTable を作るのよりは多分少ない労力で List<T> 型のオブジェクトを作れると思います。

<%@ Page Language="C#" %> <!DOCTYPE html> <script runat="server"> public class Employee { public string Id { get; set; } public string Dept { get; set; } public string Name { get; set; } } public class Role { public string Id { get; set; } public string Right { get; set; } } public class JoinedTable { public string Id { get; set; } public string Dept { get; set; } public string Name { get; set; } public string Right { get; set; } } protected void Page_Load(object sender, EventArgs erg) { if (!IsPostBack) { List<Employee> employees = new List<Employee>() { new Employee() { Id = "ID0001", Dept = "部署A", Name = "鈴木太郎" }, new Employee() { Id = "ID0002", Dept = "部署A", Name = "山田一郎" }, new Employee() { Id = "ID0003", Dept = "部署B", Name = "佐藤花子" } }; List<Role> roles = new List<Role>() { new Role() { Id = "ID0001", Right ="〇" }, new Role() { Id = "ID0003", Right ="×" }, new Role() { Id = "ID0004", Right ="〇" } }; var query = from e in employees join r in roles on e.Id equals r.Id into gj from sub in gj.DefaultIfEmpty() select new JoinedTable { Id = e.Id, Dept = e.Dept, Name = e.Name, Right = sub?.Right ?? string.Empty }; GridView1.DataSource = query; GridView1.DataBind(); } } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <form id="form1" runat="server"> <div> <asp:GridView ID="GridView1" runat="server"></asp:GridView> </div> </form> </body> </html>

【追記2】

VB.NET に直したサンプルを下にアップしておきます。変換サービスで変換して動くように手直ししただけです。なので、VB.NET の書き方としてはアレかもしれませんが、期待通りの結果になることは確認済みです。

<%@ Page Language="VB" %> <!DOCTYPE html> <script runat="server"> Public Class Employee Public Property Id() As String Get Return m_Id End Get Set m_Id = Value End Set End Property Private m_Id As String Public Property Dept() As String Get Return m_Dept End Get Set m_Dept = Value End Set End Property Private m_Dept As String Public Property Name() As String Get Return m_Name End Get Set m_Name = Value End Set End Property Private m_Name As String End Class Public Class Role Public Property Id() As String Get Return m_Id End Get Set m_Id = Value End Set End Property Private m_Id As String Public Property Right() As String Get Return m_Right End Get Set m_Right = Value End Set End Property Private m_Right As String End Class Public Class JoinedTable Public Property Id() As String Get Return m_Id End Get Set m_Id = Value End Set End Property Private m_Id As String Public Property Dept() As String Get Return m_Dept End Get Set m_Dept = Value End Set End Property Private m_Dept As String Public Property Name() As String Get Return m_Name End Get Set m_Name = Value End Set End Property Private m_Name As String Public Property Right() As String Get Return m_Right End Get Set m_Right = Value End Set End Property Private m_Right As String End Class Protected Sub Page_Load(sender As Object, erg As EventArgs) If Not IsPostBack Then Dim employees As New List(Of Employee)() From { New Employee() With { .Id = "ID0001", .Dept = "部署A", .Name = "鈴木太郎" }, New Employee() With { .Id = "ID0002", .Dept = "部署A", .Name = "山田一郎" }, New Employee() With { .Id = "ID0003", .Dept = "部署B", .Name = "佐藤花子" } } Dim roles As New List(Of Role)() From { New Role() With { .Id = "ID0001", .Right = "〇" }, New Role() With { .Id = "ID0003", .Right = "×" }, New Role() With { .Id = "ID0004", .Right = "〇" } } Dim query = From e In employees Group Join r In roles On e.Id Equals r.Id Into Group From subrole In Group.DefaultIfEmpty() Select New JoinedTable() With { .Id = e.Id, .Dept = e.Dept, .Name = e.Name, .Right = If(subrole Is Nothing, String.Empty, subrole.Right) } GridView1.DataSource = query GridView1.DataBind() End If End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <form id="form1" runat="server"> <div> <asp:GridView ID="GridView1" runat="server"></asp:GridView> </div> </form> </body> </html>

投稿2017/11/24 03:36

編集2017/11/24 08:58
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

meesa

2017/11/24 07:29 編集

回答ありがとうございます。お返事遅れておりすみません。 お恥ずかしながらVBでの開発しか経験がなく、C#コードがほぼ読めないため、 List<T>の作成とLINQの扱いに苦労しております。 (社内の情シス部門で細々と開発しています。部署の方針で、内製開発はVBに統一されているため、C#に触れる機会もほぼない環境です) 時間がかかりそうですが、いただいたヒントを元にトライしてみます。 うまくいきましたらご報告させていただきます。ありがとうございます。
退会済みユーザー

退会済みユーザー

2017/11/24 08:11 編集

変換サービスがあるので使ってみてください。 Convert Code http://converter.telerik.com/ ただし、 Right = sub?.Right ?? string.Empty の sub?.Right が変換サービスでは理解できないようですので、とりあえず sub.Right として変換にかけてみてください。変換後の VB.NET のコードは、そのままコピペして使えるかどうかは分かりませんが、人が読んで理解できる程度にはなると思います。
meesa

2017/11/24 08:11 編集

先ほどのサンプルコードを変換サービスに投入してみたのですが、エラーになってしまいます。 エラーメッセージは以下でした。 CONVERSION ERROR: Code could not be converted. Details: -- line 22 col 15: invalid TypeDecl Please check for any errors in the original code and try again. 投入したのは<script runat="server">~</script>の間部分です。 どのように対応したらよいでしょうか?
退会済みユーザー

退会済みユーザー

2017/11/24 08:13

変換できるのは C# のコードだけですよ。C# でない部分のコードをコピペしたのでは? あと、上のコメントに書いたように sub?.Right が変換サービスでは理解できないようですので、とりあえず sub.Right として変換にかけてみてください。
meesa

2017/11/24 08:30

Page_Loadの中だけでかけてもエラーになってしまいます。 sub.Rightに修正もしてありますが、エラー状況は変わりません。 CONVERSION ERROR: Code could not be converted. Details: -- line 1 col 1: EOF expected Please check for any errors in the original code and try again. 度々すみませんが、ご確認お願いします。
退会済みユーザー

退会済みユーザー

2017/11/24 08:52

自分でも試しましたが、変換は問題なかったです。使えるようにするにはかなりの手直しが必要でしたけど、人間が見て分かる程度にはなります。そこのところを話していても時間がかかるばかりですので、VB.NET に変更したサンプルを回答欄に追記しておきます。
meesa

2017/11/27 00:28

いただいたVBのサンプルソースにて、無事にやりたいことを実現することができました! LINQ部分の記述に困り果てておりましたので、VB版ソースで書いていただいたのでようやく理解ができました。本当に助かりました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問