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

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

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

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

LINQ to Entities

LINQ to Entitiesは、言語統合クエリであるLINQをEDMに行う機能を指します。C#/VBといった言語に統合されており、Visual StudioのIntelliSense機能を始めとするコーディングの様々なサポートを受けることが可能です。

LINQ

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

VB.NET

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

Q&A

解決済

2回答

11115閲覧

LINQ to Entities : LEFT JOIN の結合条件にテーブル同士の大小比較

sk_3122

総合スコア1126

Entity Framework

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

LINQ to Entities

LINQ to Entitiesは、言語統合クエリであるLINQをEDMに行う機能を指します。C#/VBといった言語に統合されており、Visual StudioのIntelliSense機能を始めとするコーディングの様々なサポートを受けることが可能です。

LINQ

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

VB.NET

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

0グッド

0クリップ

投稿2017/02/06 09:20

編集2017/02/07 06:44

###前提・実現したいこと

SQL (SQL Server) で書く際、LEFT JOIN の結合条件に テーブル同士の値で大小比較 を入れているケースがあるのですが、
これを LINQ to Entities (VB.NET) で書きたいです。

sql

1SELECT * 2FROM MAIN m 3LEFT JOIN AAA a ON ( 4 a.ID = m.ID 5 AND a.IsDeleted = 0 6 AND a.BeginYmd <= m.Ymd AND m.Ymd <= a.EndYmd -- ★こういう条件 7)

###発生している問題

LEFT JOIN の結合条件に「テーブル同士の値で大小比較」を指定する方法が分かりません。

###試したソースコード

以下の書き方だと、★の部分で

'Equals' の両辺で、少なくとも 1 つの範囲変数を参照しなければなりません。
'Equals' 演算子の一方で 1 つ以上の範囲変数 'm' を参照し、他方で 1 つ以上の範囲変数 'a' を参照する必要があります。

というエラーになります。

VBnet

1Dim query1 = ( 2 From m In dbContext.MAIN 3 Group Join a In dbContext.AAA On New With { 4 m.ID, 5 .IsDeleted = CType(0, Integer), 6 .CheckYmd = True 7 } Equals New With { 8 a.ID, 9 a.IsDeleted, 10 .CheckYmd = (a.BeginYmd <= m.Ymd AndAlso m.Ymd <= a.EndYmd) ← ★ m.*** でコンパイルエラー 11 } 12 Into _a = Group From a In _a.DefaultIfEmpty() 13 Select New With { 14 .ID = m.ID, 15 .StoreId = a.StoreID, 16 .StartYmd = a.StartYmd, 17 .EndYmd = a.EndYmd 18 } 19)

リテラル値 (IsDeletedの部分) を指定するのと同じよう名前を付けてあげればいけるかと思ったのですが、違うようでした。
検索してみたのですが、解決方法と思われるものを見つけられませんでした。


↓ これは通る

VBnet

1 ... 2 Group Join a In dbContext.AAA On New With { 3 m.ID, 4 .IsDeleted = CType(0, Integer), 5 .CheckYmd = True 6 } Equals New With { 7 a.ID, 8 a.IsDeleted, 9 .CheckYmd = True ← ★リテラル値なら問題ない 10 } 11 ...

↓ これも通る

VBnet

1 ... 2 Group Join a In dbContext.AAA On New With { 3 m.ID, 4 .IsDeleted = CType(0, Integer), 5 .CheckYmd = True 6 } Equals New With { 7 a.ID, 8 a.IsDeleted, 9 .CheckYmd = (a.BeginYmd <> "") ← ★a の値を見るのも問題ない 10 } 11 ...

↓ これは駄目

VBnet

1 ... 2 Group Join a In dbContext.AAA On New With { 3 m.ID, 4 .IsDeleted = CType(0, Integer), 5 .CheckYmd = True 6 } Equals New With { 7 a.ID, 8 a.IsDeleted, 9 .CheckYmd = (m.Ymd <> "") ← ★ここで m を見ようとすると駄目 10 } 11 ...

↓ これは駄目

VBnet

1 ... 2 Group Join a In dbContext.AAA On New With { 3 m.ID, 4 .IsDeleted = CType(0, Integer), 5 .CheckYmd = (a.Ymd <> "") ← ★左辺と右辺を入れ替えると、逆に m はOKだが a が駄目になる 6 } Equals New With { 7 a.ID, 8 a.IsDeleted, 9 .CheckYmd = True 10 } 11 ...

なんとなく駄目なパターンはわかったのですが、どうすれば目的の条件で抽出できるのかわかりません。

###追記:IEquatable を実装してみた版(うまくいかず)

VBnet

1Public Class JoinParamMainAndAAA : Implements IEquatable(Of Object) 2 Public Property ID As String = Nothing 3 Public Property StartYmd As String = Nothing 4 Public Property EndYmd As String = Nothing 5 Public Property Ymd As String = Nothing 6 Public Enum TableTypes 7 Main 8 AAA 9 End Enum 10 Public Property TableType As TableTypes 11 12 Public Overloads Function Equals(ByVal obj As Object) As Boolean Implements IEquatable(Of Object).Equals 13 ' 想定している型でなければ抜ける 14 If obj Is Nothing OrElse obj.GetType() IsNot GetType(JoinParamMainAndAAA) Then 15 Return False 16 End If 17 Dim chk = CType(obj, JoinParamMainAndAAA) 18 19 Dim m As JoinParamMainAndAAA = Nothing 20 Dim a As JoinParamMainAndAAA = Nothing 21 Select Case(Me.TableType) 22 Case TableTypes.Main: 23 ' 自分がMainの場合は相手はAAA 24 If chk.TableType = TableTypes.AAA Then 25 m = Me 26 a = chk 27 End If 28 Case TableTypes.AAA: 29 ' 自分がAAAの場合は相手はMain 30 If chk.TableType = TableTypes.Main Then 31 m = chk 32 a = Me 33 End If 34 End Select 35 If m Is Nothing OrElse a Is Nothing Then Return False 36 37 ' 比較 38 If m.ID = a.ID AndAlso 39 a.StartYmd <= m.Ymd AndAlso m.Ymd <= a.EndYmd Then 40 Return True 41 End If 42 43 Return False 44 End Function 45 46 Public Overrides Function GetHashCode() As Integer 47 Return CType(Me.ID.GetHashCode() ^ Me.Ymd.GetHashCode() ^ Me.StartYmd.GetHashCode() ^ Me.EndYmd.GetHashCode(), Integer) 48 End Function 49End Class

VBnet

1 ... 2 Group Join a In dbContext.AAA On New JoinParamMainAndAAA With { 3 .TableType = JoinParamMainAndAAA.TableTypes.Main, 4 .ID = m.ID, 5 .Ymd = m.Ymd, 6 .StartYmd = Nothing, 7 .EndYmd = Nothing 8 } Equals New JoinParamMainAndAAA With { 9 .TableType = JoinParamMainAndAAA.TableTypes.AAA, 10 .ID = a.ID, 11 .Ymd = Nothing, 12 .StartYmd = a.StartYmd, 13 .EndYmd = a.EndYmd 14 } 15 ... 16 17 ' 不要な値にもNothingをセットしているのは、そうしないと以下のエラーが出た為 18 ' The type 'TestTest.JoinParamMainAndAAA' appears in two structurally incompatible initializations within a single LINQ to Entities query. A type can be initialized in two places in the same query, but only if the same properties are set in both places and those properties are set in the same order.

実際に発行されたSQLを確認したところ、LEFT JOIN の結合が 1 = 0 となっていました。
というかEqualsの先頭にブレイクポイントをはっても止まりませんでしたが… 実装がおかしい?

SQL

1SELECT 2 1 AS [C1], 3 [Extent1].[ID] AS [ID], 4 [Extent2].[StartYmd] AS [StartYmd], 5 [Extent2].[EndYmd] AS [EndYmd] 6 FROM [dbo].[MAIN] AS [Extent1] 7 LEFT OUTER JOIN [dbo].[AAA] AS [Extent2] ON 1 = 0

追記:StackOverflowで見つけた内容

http://stackoverflow.com/questions/10642421/using-equal-and-not-equal-in-a-linq-join

A join clause performs an equijoin. In other words, you can only base matches on the equality of two keys.
Other types of comparisons such as "greater than" or "not equals" are not supported.

join節が等価結合を実行します。 言い換えれば、2つのキーが等しいかどうかに基づいて照合を行うことができます。
「より大きい」または「等しくない」などの他のタイプの比較はサポートされていません。

上記の質問内容は LEFT JOIN AAA ON (AAA.RoleName <> 'Admin') みたいなのはできないの?という内容で 私の問題とは少し違うのですが… 系統的には似てるかなと。

結局 単純な等価評価しかサポートしていないということでしょうか。

# EntityFramework を使う人は適用期間を見たりするSQLとかって組まないのでしょうか…?

###一応考えた方法

Where 句で見る…? というのを一応考えたのですが、他に方法がないものかと思い質問させて頂きました。

VBnet

1Dim query1 = ( 2 From m In dbContext.MAIN 3 Group Join a In dbContext.AAA On New With { 4 m.ID, 5 .IsDeleted = CType(0, Integer) 6 } Equals New With { 7 a.ID, 8 a.IsDeleted 9 } 10 Into _a = Group From a In _a.DefaultIfEmpty() 11 Where (a.ID = Nothing OrElse (a.BeginYmd <= m.Ymd AndAlso m.Ymd <= a.EndYmd)) 12 Select New With { 13 .ID = m.ID, 14 .StoreId = a.StoreID, 15 .StartYmd = a.StartYmd, 16 .EndYmd = a.EndYmd 17 } 18)

###補足情報(言語/FW/ツール等のバージョンなど)
開発環境等

Windows10
Visual Studio 2013
.NET Framework 4
VB.NET

足りない情報等ありましたらご指摘ください。

御存知の方がいらっしゃいましたらよろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

LINQ to Entities では単一テーブルの絞込と抽出だけ行って、結合などは一度配列なりListにしてから行うのが吉です。

投稿2017/04/17 09:54

hihijiji

総合スコア4150

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

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

sk_3122

2017/04/24 03:05

なるほど… 日付をもっていて、指定日以降の~ みたいな取り方をしたかったのですが そういう使い方にはあまり向いていなさそうですね… こういう場合は生SQL投げようかな… ありがとうございます ´ `
hihijiji

2017/04/24 03:15

Entity Framework は好きで良く使ってますが、Entity Framework を使うためにはデータモデリングの時点で Entity Framework 向けに設計しないと、まず使い物にならないんですよね。
sk_3122

2017/04/24 07:44

そういうことなのですね。 今回「既存システムのSQL部分を EntityFramework にできるならしたい」と思って色々書いてみていたのですが、 単純な結合で使えそうなところでは使って、複雑なSQLの部分は生SQL... みたいに使い分ける必要がありそうですね。 使えるケースであれば、すごく便利で私も好きです^^
guest

0

IEquatable<T>.Equalsを実装して欲しい条件の時にTrueを返すようにしてはどうでしょう
確認していないのでできないかもしれませんが..

投稿2017/02/06 22:34

dojikko

総合スコア3939

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

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

sk_3122

2017/02/07 04:10

回答ありがとうございます。 IEquatableを継承して Equals を実装してみたのですが、コンパイルは通るようになったのですがうまくいきませんでした。 (質問内容に追記しました) 質問投下後も色々調べていたのですが、やはり LINQ to Entities は等価評価はできるけど複雑な条件(<> など)はできないよ!みたいな記事をいくつか見かけました。単純な JOIN 以外は向かないということなのでしょうか ´ `
dojikko

2017/02/07 20:41

EntityFrameworkのクエリビルダがアホなのかもですね 私ではわかりませんが、式木からクエリを生成している部分に手を入れられればなんとかなる気もしないでもない
dojikko

2017/02/07 20:44

まあそこまでするならSQLを投げた方がってなりますよね
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問