1

データベースからの出力(テーブル/ビュー/プロシージャ/関数)によって生成されたクラスを含むデータレイヤーがあります。データベース内のテーブルは正規化されており、OOP 設計と同様に設計されています (「請求書」のテーブルは「ドキュメント」のテーブルと 1:1 の関係を持ち、「請求書項目」のテーブルは「ドキュメント項目のテーブルと 1:1 の関係を持ちます」 ", etc...". データベースへの/からのすべてのアクセスは、ストアド プロシージャによって行われます (単純なテーブルの場合も同様です)。

典型的なクラスは(すぐに)次のようになります。

public class DocumentItem {
    public Guid? ItemID { get; set; }
    public Guid? IDDocument { get; set; }
    public DateTime? LastChange { get; set; }
}

public class InvoiceItem : DocumentItem {
    public Guid? IDProduct { get; set; }
    public decimal? Price { get; set; }
}

問題は、データベース テーブルが OOP の多重継承に似た関係を持っていることです。ここで、すべてのデータベース出力に対して新しいクラスを実行します。ただし、すべてのデータベース出力は、データベース内の「純粋な」テーブルの組み合わせです。

理想的な解決策は、(IMHO)クラスをインターフェイスに変換し、インターフェイスの複数の実装を使用してから、メンバーを自動的に実装することです(この「テーブルクラス」にはプロパティのみがあり、プロパティの本体は常に同じです)。

例: public interface IItem { Guid? アイテムID {取得; 設定; } 日付時刻?LastChange {取得; 設定; } }

public interface IDocumentItem : IItem {
    Guid? IDDocument { get; set; }
}

public interface IItemWithProduct : IItem {
    Guid? IDProduct { get; set; }
}

public interface IItemWithRank : IItem {
    string Rank { get; set; }
}

public interface IItemWithPrice : IItem {
    decimal? Price { get; set; }
}

// example of "final" item interface
public interface IStorageItem : IDocumentItem, IItemWithProduct, IItemWithRank { }

// example of "final" item interface
public interface IInvoiceItem : IDocumentItem, IItemWithProduct, IItemWithPrice { }

// the result should be a object of class which implements "IInvoiceItem"
object myInvoiceItem = SomeMagicClass.CreateClassFromInterface( typeof( IInvoiceItem ) );

データベースには多数のテーブルが含まれており、ソリューション全体は動的にロードされるモジュール (100 以上のモジュール) で構成されています。

どのように対処するのが最善の方法だと思いますか?

編集:

"IDocumentItem" と "IItemWithPrice" (たとえば) は異なるアセンブリにあるため、部分クラスを使用することは良いヒントです。

ここで、「DocumentItem」テーブルに変更を加える場合は、すべての依存アセンブリでソース コードを再生成する必要があります。再利用はほとんどありません(多重継承が使えないため)。多数の依存アセンブリがある場合、かなり時間がかかります。

4

4 に答える 4

2

データベース スキーマからドメイン モデルを自動的に生成するのは悪い考えだと思います。

于 2009-05-06T21:33:49.337 に答える
1

データベースからの自動生成を継続し、多重継承をモデル化したい場合は、正しい考えがあると思います。ツールを変更して、多重継承とXnum実装のインターフェイスを吐き出します。

継承と集約の規則が適用されていることを他の場所で示しました。(私が理解しているように)結果のインターフェイスとクラスがどのように見えるかを正確に知っています。ビジネスルールは他の場所(おそらくビジネスルールエンジンで?)に実装されていることを理解しています。したがって、クラスの再生成では、依存コードを変更する必要はありません。ただし、これらの変更を利用する場合、または既存のプロパティが変更または削除されている場合を除きます。

しかし、あなたは終わりません。クラスには、関連するエンティティのIDが引き続き含まれます。クライアントコードを簡単にしたい場合は、次のように、関連するエンティティへの参照を用意する必要があります(関連するエンティティのIDは気にしないでください)。

public class Person{
    public Guid? PersonID { get; set; }
    public Person Parent { get; set; }
}

それはクライアントにとって物事を容易にするでしょう。あなたがそれについて考えるとき、IDから参照に移行することはとにかくあなたがしなければならない仕事です。クライアントにN回実行させるよりも、中間層で1回実行する方が適切です。さらに、これにより、コードがデータベースに依存しなくなります。

したがって、何よりも、自動生成されたクラスのOOラッパーを作成することをお勧めします。ほとんどすべてについて、このOOラッパーに対してプログラムします。データアクセス層のみが自動生成されたクラスと対話できるようにします。確かに、データベース内の継承メタデータを再利用することはできませんが(慣例で指定されていると思いますか?)、少なくとも新しいパスを作成することはありません。

対照的に、あなたが今持っているものは貧血のデータモデルかそれより悪いように見えます。

于 2010-07-28T18:14:15.153 に答える
1

つまり、ある種のミックスイン技術を本当に探しているのです。もちろん、LINQ to Entity Framework または NHibernate を使用していない理由を尋ねなければなりません。O/RM は、データベース内のデータを操作するために必要なすべてのトランザクションをサポートする API を持つ使用可能なデータ構造にリレーショナル モデルをマッピングすることで、これらの問題を処理します。しかし、私は脱線します。

動的コード生成を行うためのミックスイン テクノロジを本当に探している場合は、Mono Project の Cecil を調べてください。これは、Reflection.Emit を使用して動的クラスを構築しようとするよりも、開始するのに適した場所です。動的コード ジェネレーターは他にもありますが、ドキュメンテーションが非常に優れているため、Cecil から始めることをお勧めします。

于 2009-05-06T21:31:30.030 に答える