MongoDBおよびC#。 新機能と明白でない課題

はじめに


7月上旬、C#の公式 MongoDB ドライバーの次のバージョン(1.5)がリリースされました。 革新の中で、型付きクエリのサポートに注目する価値があります。 Expressionと組み合わせてラムダ関数を使用できるようになりました。
この記事では、私が本当に気に入っている新しい構文の例を示します(そして、C#のExpressionが本当に好きです)。また、悲しいかな、Expressionが役に立たず、通常の行に戻らなければならないクエリの例を示します。 また、なぜそうなのか、MongoDBを使用するときにC#で問題ないかどうかについても説明します。

いいね


はい、今ではなく:

ObjectId articleId = new ObjectId("dgdfg343ddfg"); IMongoQuery query = Query.EQ("_id", articleId); 

次のように書くことができます:

 ObjectId articleId = new ObjectId("dgdfg343ddfg"); IMongoQuery query = Query<Article>.EQ(item => item.Id, articleId); 

もちろん、文書の概要を表すクラスArticleの存在下で。 QueryBuilder <T>の選択に関連するすべてのメソッドは、QueryBuilderのメソッドと完全に類似していることに注意してください。 確かに、クエリを結合するには、Query.AndまたはQuery.Orを使用する必要があります。 すべてのメソッドが同じQueryBuilderを返すため、これは理解できます。 実際、好きなように組み合わせることができます。
UpdateBuilderは、適切なメソッドを持つUpdateBuilder <T>も導入しました。
以前のように:

 Article article = new Article(); IMongoUpdate update = Update.PushWrapped("Articles", article); 

どうすれば今できる:

 Article article = new Article(); IMongoUpdate update = Update<Article>.Push(item => item.Articles, article); 

私の意見では、はるかに優れています(美しさとコントロールについて話す場合)。 一般に、式ツリーは非常に強力で美しいものです。 ここでは、氷山の一角にすぎませんが、私はそれらを多くの場所で使用しました。 多くの点で、これは人間の顔の反射です。
まあ。 ここではすべてがシンプルに思えます。 あまり美しくないものに移りましょう。

ああ悲しい


値による検索のような単純なクエリはバタンと鳴ります。 ちなみに、もう少し複雑です。 たとえば、配列内の要素を検索する場合:

 IMongoQuery query = Query<Article>.ElemMatch<Comment>(item => item.Comments, builder => builder.EQ(item => item.Id, comment.Id)); 

しかし、緊張はすでに感じられています。
石炭をひっくり返しましょう。 このコンテンツのドキュメントがあります:

 _id : "s3d4f5d6sf", array1 : [{ _id : "cv434lfgd45", array2 : [{ _id : "df4gd45g43f4", name : "Logic" }, { ... }] }, { ... }] 

そして今、別の要素をarray2配列に追加するタスクがあります。 プログラム内:

1)メインドキュメントはDocモデルクラスによって記述されます
2)array1をList <Item1>に変換します。Item1はarray1の各要素のモデルクラスです
3)array2をList <Item2>に変換します。Item2はarray2の各要素のモデルクラスです

(私は意図的に文書を匿名化したため、データ構造について苦情はありませんでした)

問題を見つけることに問題はありません:

 IMongoQuery query = Query.And( Query<Doc>.EQ(item => item.Id, new ObjectId("s3d4f5d6sf")), Query<Doc>.ElemMatch<Item1>(item => item.Array2, builder => builder.EQ(item => item.Id, new ObjectId("df4gd45g43f4"))); 

しかし、更新の要求が発生しました(ドキュメントを選択し、データを追加し、データベースに書き込むオプションを意識的に検討していません。オプションがあまりにも最適ではないため。さらに、サンプルのカスケードではなくアトミック操作でデータを更新したいレコード)。 ネストされたarray2配列に到達する必要があります。 MongoDBの標準ツールを使用している場合、これを行うことができます。

 IMongoUpdate update = Update.PushWrapped<Item2>("array1.$.array2", new Item2()); 

マジックラインを回避する方法がわかりませんでした。「array1。$。Array2」という表現を長く見れば見るほど、疑わしい思いがしました。

ああ高い


遠くから始めましょう。

「静的」言語があります。 たとえば、C#。 その中で、要素の構造はコンパイル前に知られています(ほとんどの場合)。 そして、私たちが運営しているのはこれらの構造です。 より具体的には、このようなスキームのクラスを操作します。 さて、データ側には、オブジェクト(クラスのインスタンス)があります。

「動的」言語があります。 たとえば、Javascript。 それらにおいて、通常の実行は実行中のデータ構造の形成です。 一般的な場合、「空の」オブジェクトを操作し、メソッドとフィールドを追加/削除します。 そのような構造はまったく存在しません。 構築の出発点(プロトタイプ)のみがあります。

データの編成では、特定の類似性を引き出すこともできます。
リレーショナルデータベースには、ハードデータスキーマとそれらの間の依存関係があります。
ドキュメント指向では、ドキュメント、ネスト、およびリストのみがあります。

そして今、私は空想し、より粗雑な類推を与えます。
“ array1。$。Array2”の場合のExpressionでのクエリの問題は、C#でドキュメント(オブジェクト)を操作するための構造(クラス)を操作することです。 リクエストの「パワー」は、火に燃料を追加します。 選択リクエストで最初の条件のみを残す場合、必要に応じて(multiupdateでフラグを設定する)、array2配列のそれぞれに要素を追加できます。 実際、美しいクエリは(たとえ記述できたとしても)「array1。$。Array2」に変換されます。 深いレベルのネストを持つより広範なドキュメントの場合、状況は悪化するだけです。

そのようなタスクのためにExpression構文を考え出すことは不可能だと言っているのではなく、この構文がその理解性を失うように思えます。 つまり、構文部分とセマンティック部分(直感的で明確なビジネス)の間の関係が溶けます。 私は自分のプロジェクトに何が欲しいのかよくわかりません。
私にとって結論は非常に明白です。比較的単純な場合の美しい構文はクールでクールですが、より複雑な状況では、Expressionは作業を単純化せず、不確実性を増加させるだけであることがわかります。

おわりに


MongoDBの使用経験はあまりないので、説明したクエリの問題に対する解決策と、MongoDBのC#でのアーキテクチャとコードの構築に関する論理的議論/議論を記事に喜んで掲載します。

Source: https://habr.com/ru/post/J148623/


All Articles