3

n 層アプリケーション アーキテクチャを作成しています。異なるレイヤーは、相互の内部実装について何も知らず、レイヤー間の通信は、IoC/DI で支援される非常に狭いインターフェイスを介して処理されます。

ここで、ビジネス オブジェクト (ビジネス レイヤーで定義) をデータ レイヤーに渡します。ビジネス層自体は、データが実際にどこにどのように保存されているかを知りません (通常はデータベースですが、ビジネス層はそれを知っているべきではありません)。ビジネス オブジェクトは、IDataReader の実装を通じてデータ層に渡されます (このアプローチは、将来のシナリオでのデータの一括読み込みもサポートします)。データ レイヤーは IDataReader からすべてのデータを読み取り、ストアド プロシージャを呼び出してデータをデータベースに保存します (1 つのオブジェクトが保存されている場合、IDataReader は「1 行」を返します)。

実際の問題はここにあります:

IDataReader をデータ層に渡し、データをその型から切り離すだけなので、この場合、データの場所を特定する最善の方法は何ですか?

たとえば、タイプ「ユーザー」の実際のビジネス オブジェクトをデータ レイヤーに渡すと、データ レイヤーはデータをテーブル「ユーザー」に保存する必要があります。他のケースでは、ビジネス層のタイプとは関係なく、データが別の構造に保存されることがあります。

現在の実装では、ビジネス オブジェクトの型情報をデータ レイヤーに渡し、データ レイヤーがこの型を検査して、データを配置する場所を決定します。

データ層が受信データを検査してその場所を決定するのは正しい解決策ですか、それともデータ層がデータを保存できる「場所」のリストを公開する必要がありますか (enum?)?

前もって感謝します!

/説明

ここに表示されるオプションは次のとおりです。1.データレイヤーは、データを保存できる「場所」のリストを提供します2.データレイヤーは、指定された引数(そのタイプargなど)を検査し、データを保存する場所を決定します

最初のオプションのペナルティ; タイプ「製品」のビジネスオブジェクトをタイプ「ユーザー」で通常使用される構造に格納しようとするとどうなりますか

2 番目のオプションのペナルティ。タイプ「Namespace1.Namespace2.User」を、データをテーブル「User」に保存する特定のルーチンにマップする必要があります。したがって、手動で各タイプのマッピングを行います...

/説明2:

今、私はこのように取得します:

service.Retrieve(typeof(Catalog), null, catalogArgs, e => catalogConverter.Read(e));

だから私は typeof(Catalog) をデータ層に渡します...だから私はデータ層に型情報を持っています。

データレイヤーで、データベースからデータを取得するのに苦労する「アダプター」を選択する必要があります。アダプターを選択するための膨大な if/switch 構造を書くことができます...これはイライラします。また、属性を記述して次のように使用することもできます。

[TypeAdapterAttribute("Namespace1.Namespace2.Catalog, and assembly info...")]
class CatalogAdapter { ... }

次に、指定されたタイプから属性値へのマッピングを行うコードがあります...

...しかし、ハードコードされた型文字列では少し肥大化して問題があります...

助言がありますか...?

/説明3

このシステムは「プラグ可能なビジネス モジュール」によって拡張できると考えています。これらのモジュールには、base-business-logic では認識されないビジネス オブジェクト (およびいくつかのロジック) が含まれており、データ レイヤーは、「プラグされたアセンブリ」に含まれるこれらのビジネス オブジェクトを完全に認識していません。この外部ビジネス モジュールには、base-business-layer または data layer への参照がありません。この外部アセンブリからのビジネス オブジェクトが保存される (= データ レイヤーに送信される) と、データ レイヤーはデフォルトでそれを EAV スタイル (http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%) で保存します。 93value_model) データ構造を自動的に。この種のデータ構造にはパフォーマンス上の問題が発生する可能性があるため、データ層には、特定のビジネス オブジェクト タイプを専用のデータ構造 (通常はそのタイプに 1 対 1 でマッピングされたテーブル) に保存する方法が必要です。

ここでのアイデアは、多くの新しいビジネス オブジェクトを作成し、実際にデータ レイヤーに何もコーディングしなくても、それらすべてをデータ レイヤーに保存できるということです。後で、必要に応じて、選択したビジネス オブジェクトに専用のデータ構造を作成できます。

4

2 に答える 2

1

ビジネスレイヤーから切断された独自のデータベースレイヤーを作成する場合は、コントラクトを含む別のアセンブリを導入することもできます。

List<Customer> customers = DB.LoadCustomers();

データ層は、ジェネリック型パラメーターを操作し、を介してビジネスオブジェクトに関する情報を取得できますReflection。データレイヤーはビジネスコンポーネントへの参照を必要としないため、これによりレイヤーを適切に分離できます。

List<Customer> customers = DataContext.Query<Customer>.Load();

また

Customer customer = DataContext.Query<Customer>.Load(custID);

O/Rマッパーは通常このように機能します

List<Customer> customers = Context.Query<Customer>()
    .Where(cust => cust.Name.StartsWith("A"))
    .OrderBy(cust => cust.Name)
    .ToList();

これらの例では、データ層がビジネスオブジェクトを作成して埋めます。それ以外の場合、ビジネスレイヤーはテーブルの列名を知っている必要があります。

(注:ここでは特定のデータインターフェイスについては言及していません。)


アップデート:

ビジネスレイヤーから切り離された独自のデータベースレイヤーを作成する場合は、コントラクトを含む別のアセンブリを導入することもできます。

public interface ICustomer
{
    string LastName { get; set; }
    string FirstName { get; set; }
    ...
}

データ層とビジネス層の両方が、これらの契約への参照を持ちます。

データレイヤーでは、次のようなメソッドがあります

public List<T> LoadAll<T>(Func<T> create)
{
    var list = new List<T>();
    if (T is ICustomer) {
        string sql = "SELECT * FROM tblCustomer";
        ...
        while (reader.NextResult()) {
            ICustomer cust = (ICustomer)create();
            cust.FirstName = reader.GetString("FirstName");
            ...
            list.Add((T)cust);
        }
    } else if (T is IOrder) {
        ...
    }
    return list;
}

ビジネスレイヤーでは、

List<ICustomer> customers = DbLayer.LoadAll<ICustomer>(() => new Customer());

これで、データレイヤーは、顧客クラスを知らなくても、ビジネスレイヤーアセンブリを参照しなくても、顧客と連携できます。

于 2012-03-18T19:52:17.397 に答える
1

オブジェクトをデータ ストアにマップするには、ORM (Entity Framework、NHibernate) またはマイクロ ORM (PetaPoco、Dapper) を使用することをお勧めします。
それを調べて、特定の質問がある場合は撃ってください。

更新:あなたが求めているものを手に入れたと思います。
タイプごとにデータレイヤーで新しいメソッドを定義する必要があります。そう:

public User GetUserById(int id);
public void SaveUser(User user);
public Product GetProductById(int id);
public void SaveProduct(Product product);
于 2012-03-18T19:43:00.043 に答える