Protocol Buffers の IDL で定義された型のオブジェクトを MongoDB に格納できるかどうかを検証しています。gRPC で受け取ったオブジェクトをそのまま MongoDB に格納するようなストーリーを想定しています。
単純な型であれば特に問題なく格納できるのですが、やはりいろいろな前提や制限があるようです。
MongoDB 公式の C# 実装である MongoDB.Driver (2.5.1) を使用しています。BSON ではなく、タイプセーフな方法でどのように実装できるかを考えます。MongoDB.Driver はバージョンによって仕様が大きく異なるようで、注意が必要です。
Id プロパティ・フィールドが必要
ドキュメントとして格納するルートオブジェクトの型に Id という名称のプロパティやフィールドが存在しない場合、"Id Element '_id' does not match any field or property" というエラーが発生します。
Id の値が _id というフィールドで格納されます。Id が存在しなくても _id というフィールドが自動的に追加されて格納されるのですが、Find メソッドなどでエラーが発生します。事実上、Id が必須であると思われます。
なお、Id の型によって MongoDb に格納されるときの型が変わります。System.Guid を使いたいところですが、Protocol Buffers ではサポートされていません。
- System.String → 文字列
- System.Guid → バイト配列
- proto ファイルの message から定義された型 → ネストされたオブジェクト
repeated フィールドは格納不可
repeated が指定されたフィールドを含む場合、UpdateMany メソッドなどで "Unable to determine the serialization information" というエラーが発生します。
repeated が指定されているフィールドは Repeatable<T> 型のプロパティとして定義されますが、setter がないためエラーになるようです。Repeatable<T> 型自体がシリアライズできないわけではなく、setter があれば Array として格納できます。一方、InsertMany メソッドなどでは setter がないプロパティは格納対象外になるようで、エラーは発生しませんが格納もされません。
Grpc.Tools で自動生成するたびにソースコードを修正するのは現実的ではありませんので、partial ファイルに setter つきのプロパティを追加する方法が妥当でしょうか。とはいえ、一つ一つ定義するのも確実性に欠けます。自動生成の過程で解決できるのがベストだと思います。
Grpc.Toolsで自動生成されたコード
public RepeatedFieldTags { get { return tags_; } }
partial ファイルで追加したコード
この場合、FilterDefinition や UpdateDefinition で Tags プロパティの代わりに TagsSerializable プロパティを使うことになります。[BsonElement("Tag")] public RepeatedFieldTagsSerializable { get { return Tags; } private set { Tags.Clear(); if (value!=null) { Tags.AddRange(value); } } }
2018/05/03 追記
setter のスコープは private でもよいようです。
0 件のコメント:
コメントを投稿