背景:来月、C#
のコンテキストでLINQ
について、または少なくとも3回の講演を行います。人々が理解するのが難しいと感じるもの、または誤った印象を与える可能性のあるものに基づいて、どのトピックにかなりの注意を払う価値があるかを知りたい。式ツリー(および通常はLINQ
)を使用してクエリをリモートで実行する方法の例を除き、SQL
からIQueryable
またはEntity Frameworkについては特に説明しません。
それで、LINQ
について何が難しいと思いましたか?誤解については何を見ましたか?例は次のいずれかになりますが、ご自身を制限しないでください!
C#
コンパイラがクエリ式を処理する方法IQueryable
遅延実行
延期された実行の概念は今までに打ち負かされるべきだと知っていますが、この例は実際にそれを実際に把握するのに役立ちました:
static void Linq_Deferred_Execution_Demo()
{
List<String> items = new List<string> { "Bob", "Alice", "Trent" };
var results = from s in items select s;
Console.WriteLine("Before add:");
foreach (var result in results)
{
Console.WriteLine(result);
}
items.Add("Mallory");
//
// Enumerating the results again will return the new item, even
// though we did not re-assign the Linq expression to it!
//
Console.WriteLine("\nAfter add:");
foreach (var result in results)
{
Console.WriteLine(result);
}
}
上記のコードは次を返します。
Before add:
Bob
Alice
Trent
After add:
Bob
Alice
Trent
Mallory
LINQ
からSQL
だけではなく、機能は言語に組み込まれたSQL
パーサーだけではありません。
ビッグO表記 。 LINQを使用すると、何をしているのかわからない場合、O(n ^ 4)アルゴリズムを気付かずに非常に簡単に記述できます。
Lambda
式は式ツリーと匿名デリゲートの両方に解決できるため、同じ宣言lambda
式をIEnumerable<T>
拡張メソッドとIQueryable<T>
拡張メソッドの両方に渡すことができると思います。
Single()
、SingleOrDefault()
などの多くのLINQ拡張メソッドがラムダを使用するオーバーロードを持っていることを理解するには、長すぎてwayでした。
できるよ :
Single(x => x.id == id)
そして、これを言う必要はありません-いくつかの悪いチュートリアルが私をする習慣になった
Where(x => x.id == id).Single()
LINQ to SQLでは、DataContext、その使用方法、使用方法を理解していない人々が常にいます。永続オブジェクトではなく、作業単位オブジェクトであるDataContextが表示されない人が多すぎます。
私は人々が各操作のために新しい時間を作るのではなく、DataContext /セッションit /などをシングルトン化しようとする多くの時間を見てきました。
そして、IQueryableが評価される前にDataContextを破棄しますが、それはDataContextよりもIQueryableを理解していない人々にとってはより重要なことです。
私が多くの混乱を見る他の概念は、クエリ構文と式構文です。その時点で最も簡単な方法を使用します。多くの場合、式構文にこだわっています。結局のところ、多くの人は最終的に同じものを生成することを認識していません。結局、QueryはExpressionにコンパイルされます。
the LINQの誤解されている部分は、それが言語拡張であり、データベースの拡張や構成ではないということです。
LINQ
はLINQ to SQL
をはるかに超えています。
私たちのほとんどがコレクションでLINQ
を使用したので、二度と戻りません!
LINQ
は、2.0のGenericsおよび3.0のAnonymous Types以来、.NETにとって最も重要な機能です。
そして、Lambdaがあるので、並列プログラミングを待つことができません!
私は、表現ツリーとは何か、そしてその理由を知る必要があるかどうかを知りたいと思っています。
私はLINQを初めて使用します。ここに私が最初の試みでつまずいたものがあります
元々気がつかなかったのは、LINQ構文がIEnumerable<T>
またはIQueryable<T>
を必要としないことで、LINQは単なるパターンマッチングです。
alt text http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png
答えはここにあります (いいえ、私did n'tそのブログを書いて、Bart De Smetはしました、そして彼は私が見つけたLINQの最高のブロガー)。
「let」コマンド(使用法を見つけたことがありません)およびSelectMany(使用したことがありますが、正しく実行したかどうかはわかりません)にまだ問題があります
Linqプロバイダー間の抽象化がいつ漏れるかを理解する。オブジェクトでは機能するものの、SQLでは機能しないものもあります(例:.TakeWhile)。一部のメソッドはSQL(ToUpper)に変換できますが、他のメソッドは変換できません。一部の手法はオブジェクトでより効率的ですが、他の手法はSQLでより効果的です(異なる結合方法)。
いくつかのこと。
OK、需要があるため、Expressionの一部を作成しました。私はブロガーとLiveWriterがどのようにそれをフォーマットするために共謀したかについて100%満足していませんが、今のところは...
とにかく、ここに行く...私は、特に人々がより多くの情報を望んでいる領域がある場合は、フィードバックが欲しいです。
ここにある 、好きか嫌いか...
特にLINQ to SQLからのエラーメッセージの一部は、かなり紛らわしい場合があります。 笑顔
他の人と同じように、私は延期された実行に数回噛まれました。私にとって最も紛らわしいのは、SQL Serverクエリプロバイダーと、それでできることとできないことです。
時々空の10進数/お金の列でSum()を実行できないという事実に、私はまだ驚いています。 DefaultIfEmpty()を使用しても機能しません。 :(
LINQで取り上げるのは、パフォーマンスの面で問題を抱えることができるのは素晴らしいことだと思います。たとえば、LINQカウントをループ条件として使用するのは、本当に賢くありません。
IQueryableは、Expression<Func<T1, T2, T3, ...>>
とFunc<T1, T2, T3, ...>
の両方を受け入れますが、2番目の場合のパフォーマンスの低下についてのヒントは提供しません。
これが私が意味することを示すコード例です:
[TestMethod]
public void QueryComplexityTest()
{
var users = _dataContext.Users;
Func<User, bool> funcSelector = q => q.UserName.StartsWith("Test");
Expression<Func<User, bool>> expressionSelector = q => q.UserName.StartsWith("Test");
// Returns IEnumerable, and do filtering of data on client-side
IQueryable<User> func = users.Where(funcSelector).AsQueryable();
// Returns IQuerible and do filtering of data on server side
// SELECT ... FROM [dbo].[User] AS [t0] WHERE [t0].[user_name] LIKE @p0
IQueryable<User> exp = users.Where(expressionSelector);
}
LINQの最も誤解されている(または理解されていないはずの)側面は、IQueryableおよびカスタムLINQプロバイダーです。
私はしばらくLINQを使用していますが、IEnumerableの世界では完全に快適であり、LINQのほとんどの問題を解決できます。
しかし、IQueryable、Expressions、およびカスタムlinqプロバイダーについて調べて読み始めたとき、頭を回転させました。かなり複雑なロジックを確認したい場合は、LINQ to SQLの仕組みをご覧ください。
私はLINQのその側面を理解することを楽しみにしています...
それが誤解とみなされるかどうかはわかりませんが、私にとっては、単に不明です。
DataLoadOptionsについて、また特定のクエリを作成するときにどのテーブルを結合するかを制御する方法について学びました。
詳細については、こちらを参照してください: MSDN:DataLoadOptions
ほとんどの人が言ったように、最も誤解されている部分は、LINQがT-SQLの単なる代替品であると想定していることだと思います。 considers自分がTSQLの第一人者である私のマネージャーは、プロジェクトでLINQを使用することを許可しません。
ループをネストするのがどれほど簡単かは、誰もが理解しているとは思いません。
例えば:
from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem
クエリの実行時にvarは何を表しますか?
iQueryable
、iSingleResult
、iMultipleResult
、または実装に基づいて変更されますか。 C#での動的な型付けと標準的な静的な型付け(と思われる)の使用については、いくつかの推測があります。
group by
はまだ頭を回転させます。
deferred execution に関する混乱は、いくつかの簡単なLINQベースのコードをステップ実行し、ウォッチウィンドウで遊んで解決する必要があります。
IQueryable
はメソッド呼び出しであるため(still SQL以外は翻訳できないため)チェーンできず、回避することはほとんど不可能であるという事実は、気が遠くなるほど作成されます。 DRYの大きな違反。コンパイルされたクエリを持たないアドホック用にIQueryable
が必要です(重いシナリオのためにコンパイルされたクエリしかありません)が、コンパイルされたクエリではそれらを使用できず、代わりに通常のクエリを記述する必要があります再び構文。現在、2つの場所で同じサブクエリを実行しています。何か変更があった場合は、両方を更新することを忘れないでください。悪夢。
LINQ to SQLについての1番目の誤解は、SQLを有効に活用するためにはまだSQLを知っている必要があるということです。
Linq to Sqlについて誤解されているもう1つの点は、データベースのセキュリティを不条理にまで下げて機能させる必要があるということです。
3番目のポイントは、Linq to SqlをDynamicクラス(クラス定義が実行時に作成されること)と共に使用すると、膨大な量のジャストインタイムコンパイルが発生することです。これはパフォーマンスを完全に損なう可能性があります。
遅延読み込み。
トランザクション(TransactionScopeを使用しない)
ほとんどの人が言ったように、最も誤解されている部分は、LINQがT-SQLの単なる代替品であると想定していることだと思います。自分をTSQLの第一人者と見なしている私のマネージャーは、プロジェクトでLINQを使用することを許可しません。
前述のように、遅延読み込みと遅延実行
LINQ to ObjectsおよびLINQ to XML(IEnumerable)とLINQ to SQL(IQueryable)との違い
HOWすべてのレイヤーでLINQを使用してデータアクセスレイヤー、ビジネスレイヤー、プレゼンテーションレイヤーを構築します。
理解構文「魔法」。理解構文はどのようにメソッド呼び出しに変換され、どのメソッド呼び出しが選択されますか。
たとえば、次のようにします。
from a in b
from c in d
where a > c
select new { a, c }
メソッド呼び出しに変換されます。
特にWebアプリケーションのパフォーマンスに関して、匿名型に関する明確な情報を見つけるのは難しいと感じました。また、より良い実用的なラムダ式の例と、クエリとパフォーマンス関連のトピックの「方法」セクションをお勧めします。
私の簡単なリストが役立つことを願っています!
LinqがSQL構文のように単純な左外部結合を処理しない理由を説明します。この記事を参照してください: LINQを使用した左結合の実装 、 方法:左外部結合の実行(C#プログラミングガイド) 言語に対する敬意は消え、私はそれがただちに消えていくものに過ぎないと判断しました。これらの戦場で証明されたプリミティブを持たない構文を使用したい深刻な人はいません。この種の集合演算がサポートされない理由を説明できれば。私はより良く、よりオープンマインドな人になります。
実世界のプログラムではめったに使用されない「理解するのが難しい」ものに時間を浪費するのではなく、LINQの最も一般的に使用される機能-ラムダ式と匿名型にもっと注意を払うべきだと思います。
これはもちろん「最も難しい」ものではなく、リストに追加するものです。
ThenBy() extension method
その実装を見ることなく、私はそれがどのように機能するかについて最初は戸惑います。誰もがSQLでコンマ区切りのソートフィールドがどのように機能するかをよく理解しています。前のソートフィールドが何であったかをどのように「知る」ことができますか?.
今すぐ調べに行きます...
「式ツリーの作成」は難しいと思います。 LINQ、LINQ to SQL、およびADO.Netを使用すると、何ができるかという点で私を悩ます多くのことがあります。
LINQ2SQLの場合:生成されたSQLのいくつかを理解し、優れた(高速の)SQLに変換されるLINQクエリを作成します。これは、LINQクエリの宣言的性質と、既知の環境(SQL Server)で高速に実行する必要があるという現実とのバランスをとる方法を知るという大きな問題の一部です。
LINQコードのごく小さなものを変更することで、まったく異なるSQL生成クエリを取得できます。条件ステートメントに基づいて式ツリーを作成している場合(つまり、オプションのフィルター条件を追加している場合)、特に危険です。
3つのフィールドを持つテーブルがあるとします。 A、B&C(これらは整数で、テーブル名は「Table1」です)。
次のように表示します。
[A、B、C]
次に、次のような結果を取得します。
[X = A、Y = B + C]
そして、そのようなクラスがあります:
public class Temp
{
public Temp(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X { get; private set; }
public int Y { get; private set; }
}
次に、次のように使用します。
using (MyDataContext db = new MyDataContext())
{
var result = db.Table1.Select(row =>
new Temp(row.A, row.B + row.C)).ToList();
}
生成されるSQLクエリは次のとおりです。
SELECT [t0].[A] AS [x], [t0].[B] + [t0].[C] AS [y]
FROM [Table1] AS [t0]
Tempの.ctorを変換します。 "row.B + row.C"(さらに...)にクラスコンストラクターの "y"パラメーターを設定することを知っています。
これらの翻訳は私にとって非常に興味があります。私はそれが好きで、そのような翻訳者(LINQ to Something)を書くのは少し難しいと思います!
もちろん!悪いニュースです。LINQto Entities(4.0)は、パラメーターを持つコンストラクターをサポートしていません。 (何故なの?)
どちらが高速か、Tsql Sprocsを使用したインラインLinq-to-SqlまたはLinq-to-Sql
...そして、サーバー側(Sproc)またはクライアント側(インラインLinq)クエリを使用した方が良い場合があります。
クエリ式の構文はLINQ機能のサブセットのみをサポートしているため、拡張メソッドのチェーンをたまに避けることはできません。例えば。 Distinct
メソッドは、クエリ式構文を使用して呼び出すことはできません。 Distinct
メソッドを使用するには、拡張メソッドを呼び出す必要があります。一方、多くの場合、クエリ式の構文は非常に便利なので、それもスキップしたくないでしょう。
LINQに関する講演には、ある構文を他の構文よりも優先するタイミングと、それらをどのように混在させるかに関する実用的なガイドラインが含まれます。
IQueryableはメソッド呼び出しであるため(SQL以外の翻訳はできませんが!)、IQueryableをチェーン化できず、回避することはほぼ不可能であるという事実は、気が遠くなるほどDRYの大きな違反になります。クエリをコンパイルしていないアドホック用にIQueryableが必要です(重いシナリオ用にコンパイルしたクエリしかありません)が、コンパイルされたクエリでは使用できず、代わりに通常のクエリ構文を再度記述する必要があります。現在、2つの場所で同じサブクエリを実行しています。何か変更があった場合は、両方を更新することを忘れないでください。悪夢。