6

この問題は、Entity Framework や NHibernate などの ORM で簡単に解決できますが、MongoDb の c# ドライバーには既成の解決策が見当たりません。特定のオブジェクト B が変更されると、それを参照するすべての A が変更を認識する必要があるように、別のコレクションに格納する必要があるオブジェクト タイプ B を参照するタイプ A のオブジェクトのコレクションがあるとします。つまり、このオブジェクトの関係を正規化する必要があります。同時に、クラス内の A によって B が参照される必要があります。ID ではなく、以下に示すような型参照によって参照されます。

public class A
{
   public B RefB { get; set; }
}

この参照の一貫性をすべて自分で処理する必要がありますか? その場合、どのアプローチを使用するのが最適ですか? B の Id と B 参照の両方をクラスに保持し、何らかの方法でその値を同期する必要がありますか:

public class A
{
    // Need to implement reference consistency as well
    public int RefBId { get; set; }

    private B _refB;
    [BsonIgnore]
    public B RefB
    {
        get { return _refB; }
        set { _refB = value; RefBId = _refB.Id }
    }
}

リレーショナル データベースがこのケースに最も適していると誰かが言うかもしれませんが、私は実際に MongoDb のようなドキュメント Db を使用する必要があります。それは多くの問題を解決し、ほとんどの場合、プロジェクト用に非正規化されたオブジェクトを格納する必要があります単一のストレージ内に混合設計が必要です。

4

3 に答える 3

6

これは主にアーキテクチャの問題であり、おそらく個人的な好みに少し依存します。私は長所と短所を調べようとします(実際には短所だけで、これはかなり独断的です):

データベース レベルでは、MongoDB には参照整合性を強制するツールが用意されていないため、自分で行う必要があります。次のようなデータベース オブジェクトを使用することをお勧めします。

public class DBObject 
{
    public ObjectId Id {get;set;}
}

public class Department : DBObject 
{
  // ...
}

public class EmployeeDB : DBObject
{
    public ObjectId DepartmentId {get;set;}
}

何があっても、データベース レベルでこのような単純な DTO を使用することをお勧めします。追加の砂糖が必要な場合は、少しコピーすることを意味しても別のレイヤーに入れます. DB オブジェクトのロジックには、ドライバーがオブジェクトをハイドレートする方法を十分に理解している必要があり、実装の詳細に依存する必要がある場合があります。

さて、より「インテリジェントな」オブジェクトを使用するかどうかは好みの問題です。実際、多くの人は、強く型付けされた auto-activating アクセサーを使用することを好みます。

public class Employee
{
    public Department 
    { get { return /* the department object, magically, from the DB */ } }
}

このパターンには多くの課題があります。

  • Employeeデータベースからオブジェクトをハイドレートできるようにするには、クラス (モデル クラス) が必要です。DBを注入する必要があるか、データベースアクセス用の静的オブジェクトが必要なため、これも注意が必要です。
  • へのアクセスはDepartment非常に安価に見えますが、実際にはデータベース操作がトリガーされ、遅くなる可能性があり、失敗する可能性があります。これは発信者から完全に隠されています。
  • 1 対 n の関係では、事態はさらに複雑になります。たとえば、 ?Departmentのリストも公開します。Employeesもしそうなら、それは本当にリストですかMongoCursor?
  • さらに悪いことに、どの種類のキャッシングを使用する必要があるかは通常明確ではありません。あなたが得るとしましょうmyDepartment.Employee[0].Department.Name。明らかに、このコードはスマートではありませんが、いくつかの特殊なメソッドを含むコール スタックがあると想像してください。もっと隠されていても、彼らはそのようにコードを呼び出すかもしれません。現在、素朴な実装は、実際には、ref'dDepartmentを再度逆シリアル化します。それは醜いです。一方、実際にオブジェクトを再取得する必要がある場合があるため、積極的にキャッシュすることは危険です。
  • 最悪の事態:アップデート。これまでのところ、課題は主に読み取り専用でした。ここで、 and を呼び出すemployeeJohn.Department.Name = 'PixelPushers'としましょうemployeeJohn.Save()。それは部門を更新しますか?もしそうなら、john への変更は最初にシリアル化されますか、それとも従属オブジェクトへの変更の後にシリアル化されますか? バージョン管理とロックはどうですか?
  • 多くのセマンティクスは実装がemployeJohn.Department.Employees.Clear()難しく、扱いにくい場合があります。

多くの ORM は一連の複雑なパターンを使用してこれらの操作を許可しているため、これらの問題を回避することは不可能ではありません。しかし、ORM は通常、10 万行から 100 万行をはるかに超えるコード行 (!) の範囲にあり、そのような時間があるとは思えません。RDBMS では、関連するオブジェクトをアクティブ化し、sth を使用する必要があります。ORM のように、明細項目のリストなどを請求書に埋め込むことはできないため、1:n または m:n の関係はすべて結合を使用して表す必要があります。これは、オブジェクト関係の不一致と呼ばれます。

私が理解しているドキュメント データベースの考え方は、RDBMS のように不自然にモデルを分割する必要がないということです。それでも、「オブジェクトの境界」があります。データ モデルを接続されたノードのネットワークと考える場合、課題は、現在データのどの部分で作業しているかを知ることです。

個人的には、この上に抽象化レイヤーを配置しないことを好みます。その抽象化は漏れやすく、実際に何が起こっているかを呼び出し元から隠し、すべての問題を同じハンマーで解決しようとするからです。

NoSQL の考え方の 1 つは、JOIN ハンマーを目に見えるテーブルに単純に適用することはできないため、クエリ パターンをデータ モデルに注意深く一致させる必要があるということです。

したがって、私の意見は次のとおりです。薄いレイヤーに固執し、データベース操作のほとんどをサービスレイヤーで実行します。ロック、mvcc、カスケード更新などを追加する必要があるとすぐにバラバラになる複雑なドメイン モデルを設計する代わりに、DTO を移動します。

于 2013-09-30T17:06:02.803 に答える
1

リレーショナル データベースとはまったく異なるアーキテクチャの概念に基づくドキュメント データベース。NoSQL データベースの主な原則は、関係ではなく集約です。したがって、説明したようなデータベースで正規化を期待するべきではありません。

問題は手動でのみ追跡する必要があります。NoSQL には参照整合性のようなものはありません。

于 2013-10-06T20:45:26.633 に答える