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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C#

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

LINQ

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

Q&A

解決済

4回答

10211閲覧

やや複雑めなLINQ式の書き方について

takagitakashi

総合スコア15

C#

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

LINQ

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

0グッド

1クリップ

投稿2017/04/27 04:17

編集2017/04/27 04:41

###前提・実現したいこと
LINQ式の書き方
###発生している問題・エラーメッセージ
以下のようなエラーメッセージが出ます。

[2017-04-27 11:04:58.5497][ERROR][****] サービスでエラーが発生しました。 System.Data.Entity.Core.EntityCommandExecutionException: ストア プロバイダーのデータ リーダーから読み取り中にエラーが発生しました。詳細については、内部例外を参照してください。 ---> System.Data.SqlClient.SqlException: リンク サーバー "******_H_LINK" の OLE DB プロバイダー "OraOLEDB.Oracle" に対するクエリ "SELECT hogehoge....." を実行できません。 リンク サーバー "*******_H_LINK" の OLE DB プロバイダー "OraOLEDB.Oracle" から、メッセージ "" が返されました。 場所 System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) 場所 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) 場所 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) 場所 System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) 場所 System.Data.SqlClient.SqlDataReader.TryHasMoreRows(Boolean& moreRows) 場所 System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more) 場所 System.Data.SqlClient.SqlDataReader.Read() 場所 System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.StoreRead() --- 内部例外スタック トレースの終わり ---

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

c#

1private bool hasSomething {get;set;} 2..... 3var result = context.VIEW_TABLE 4 .WHERE(......) 5 .WHERE(x => 6 !hasSomething 7 || (hasSomething && x.HOGE == hoge) 8 ) 9 .WHERE(.....)

###試したこと
上記ソースを以下に変更したところ動作した。

c#

1private bool hasSomething {get;set;} 2..... 3var result = context.VIEW_TABLE 4 .WHERE(......) 5 .WHERE(x => 6 (!hasSomething && x.HOGE == x.HOGE) 7 || (hasSomething && x.HOGE == hoge) 8 ) 9 .WHERE(.....)

###聞きたいこと
これはC# (というかLINQ)の バグでしょうか?
それとも何か書き方がおかしいでしょうか?
###補足情報(言語/FW/ツール等のバージョンなど)
VISUAL STUDIO 2013 (C# Ver.5)
DB: SQL SERVER 2014
※問題のテーブルは、LINKテーブルのVIEWであり、LINK元はORACLEを使用しています

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

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

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

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

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

guest

回答4

0

LINQ to Entities クエリ内の式

Entity Framework に対するクエリの一部である式は、ObjectQuery<T> および基になるデータ ソースでサポートされている演算に制限されます。

クエリ式は SQL に変換され、Oracle(基になるデータソース)で実行されます。

投稿2017/04/27 04:34

Zuishin

総合スコア28656

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

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

takagitakashi

2017/04/27 05:28 編集

つまり、SQL文として、たとえば、 ```sql SELECT * FROM table WHERE true or (false and col1 = 'x') ``` もしくは ```sql SELECT * FROM table WHERE false or (true and col1 = 'x') ``` のようなものが実行されるものと考えているのですが、違いますでしょうか? 動作しているものは、おそらく ```sql SELECT * FROM table WHERE (true and col1 = col1) or (false and col1 = 'x') ``` が実行されて結果が返っているものと考えております。
takagitakashi

2017/04/27 05:28

う、、markdown 記法使えないのな><
Zuishin

2017/04/27 08:32

hasSomething の中身もどのような SQL に変換されたのかもよくわからないので何とも言えませんが、https://www.kekyo.net/2013/12/11/503 を参考に ToString() すると SQL が得られると思いますので確認してみてください。
takagitakashi

2017/04/28 06:17

Whereメソッドのラムダ式にそもそも(やや)複雑なものを書かないようにすれば、本問題には遭遇せず、またそうするべきと思いますので、もともとの疑問を持つことをやめました。 回答ありがとうございました。
Zuishin

2017/04/28 06:23

それも手ですね。ただ不要なデータをアプリケーション側に渡すために、十分考慮して書かないとパフォーマンス(メモリ効率・速度)が落ちる場合があるので注意してください。
guest

0

ベストアンサー

自動化手段を使うならZuishinさんの方法で中身を見れるようにしておきたいですね。
自分はLinq To SQL を使わないので一つだけ。

Linqを使うなら以下のように絞り込みを足していくこともできます。

C#

1IQueryable</*type*/> query = context.VIEW_TABLE; 2 3query = query.Where(......); 4 5if (hasSomething) 6{ 7 query = query.Where(x => x.HOGE == hoge); 8} 9 10query = query.Where(.....); 11 12var result = table.Select ...

もしくは、書き味重視なら以下のようなシンタックスシュガーをExtensionで用意してあげれば

C#

1IQueryable<T> WhereIf(this IQueryable<T> query, bool enable, Expression<Func<T, Boolean>> predicate) 2{ 3 return (enable) ? query.Where(predicate) : query; 4}

以下のようになります。

C#

1var result = context.VIEW_TABLE 2 .Where(......) 3 .WhereIf(hasSomething, x => x.HOGE == hoge) 4 .Where(.....)

SQL文自体は上手くパラメータ化して XX or XX としておけばクエリコンパイルのキャッシュが溜まるかもしれませんし、どちらが良いかは分からないですが…。
SQLプロファイラはキレイな方が見やすいですし、一応ということで。

投稿2017/04/28 02:09

haru666

総合スコア1591

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

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

takagitakashi

2017/04/28 06:14

確かにこちら(拡張メソッド)のほうが、変なパラメータを導入して、長いラムダ式にするより見通しが良いですね! そして、ラムダ式は極力複雑にならないようにしたいと思います。 ありがとうございました。
guest

0

LINQ TO SQL の範囲から出て、ふつうのLINQをしたいなら、
ToArray()を挟むといいよ。切り替わるから。

投稿2017/04/27 06:52

kiichi54321

総合スコア1984

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

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

takagitakashi

2017/04/27 07:39

大量のWHEREメソッドで絞りこまなければならず、SQLの範囲から抜け出せそうにありませ ん。 そもそも、記載した二つの例(の内の2番目)にあるような書き方をしないといけない理由が知りたいので、一時リストを作成する、というようなやり方を知りたいわけではありません。 それなら自力で何とかなりますんで。
guest

0

失礼しました。外してました・・・


2番目のWhereでなぜ副作用を起こす必要があるのかという点は気になりましたが・・・

hasSomethingが何を意味するか、xが何か、x.HOGEが何か不明なのでなんともいえないと思います。
前後の動きが見えないと副作用などの影響が見えないので推測が困難ではないでしょうか?

例えば自分にはhasSomethingがboolのローカル変数なのかプロパティーなのかさらに副作用を持つプロパティーなのかもわかりません。そうしたところを疑いだすときりがなくなる気がしますが・・・

投稿2017/04/27 04:35

編集2017/04/27 04:36
KSwordOfHaste

総合スコア18392

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

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

takagitakashi

2017/04/27 04:39

回答ありがとうございます。hasSomething について何も記載していませんでしたね。。すいません。 別途修正しておきます。 xについては、LINQ式で渡されてくるレコードの仮引数です。 いずれにしても副作用は無いと考えております。
KSwordOfHaste

2017/04/27 04:56 編集

いえ、Zuishinさんの回答をみてDBアクセスとしてのLINQの意味について自分が無知であることに気づき・・・ お恥ずかしい限りです。
Zuishin

2017/04/27 08:34

hasSomethingが何を意味するか、xが何か、x.HOGEが何か不明なのでなんともいえないのはまさにその通りで、何も間違ったことはおっしゃっていないと思いました。
KSwordOfHaste

2017/04/27 08:40

DBに対するLINQでもそうした点は共通ということですね。コメントありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問