16

これを行うための最もクリーンな方法を見つけようとしています。

現在、私は顧客オブジェクトを持っています:

public class Customer
{
    public int Id {get;set;}
    public string name {get;set;}
    public List<Email> emailCollection {get;set}
    public Customer(int id)
    {
        this.emailCollection = getEmails(id);
    }
}

次に、私の Email オブジェクトもかなり基本的なものです。

public class Email
{
    private int index;
    public string emailAddress{get;set;}
    public int emailType{get;set;}
    public Email(...){...}
    public static List<Email> getEmails(int id)
    {
        return DataAccessLayer.getCustomerEmailsByID(id);
    }
}

DataAccessLayer は現在データベースに接続しており、SqlDataReader を使用して結果セットを反復処理し、新しい Email オブジェクトを作成して、完了時に返される List に追加します。

では、これをどこでどのように改善できますか?

代わりに DataAccessLayer に DataTable を返させ、それを Email オブジェクトに任せて解析し、List を顧客に返す必要がありますか?

「Factory」はおそらく間違った言葉だと思いますが、DataAccessLayer から DataTable を取得し、リストを Email オブジェクトに返す別のタイプの EmailFactory を使用する必要がありますか? 私はそのようなことは冗長に聞こえると思います...

私の Email.getEmails(id) を静的メソッドとして使用することは、これでも適切な方法ですか?

通常は単純なタスクに最適な「パターン」を見つけて適用しようとすることで、私は自分自身を捨てているだけかもしれません.

ありがとう。


ファローアップ

ドメイン/ビジネス オブジェクトが既存のデータベースから ID で顧客レコードを抽出する実際の例を作成しました。nhibernate の xml マッピング ファイルは非常に優れています。チュートリアルに従ってセッションとリポジトリ ファクトリをセットアップした後は、データベース レコードのプルは非常に簡単でした。

ただし、パフォーマンスが大幅に低下していることに気付きました。

私の元のメソッドは、結果セットをドメイン/ビジネス オブジェクトに解析する DAL オブジェクトによって呼び出される DB 上のストアド プロシージャで構成されていました。

1 つの顧客レコードを取得するのに 30 ミリ秒かかる元の方法を記録しました。次に、同じレコードを取得するのに 3000 ミリ秒かかる nhibernate メソッドのクロックを記録しました。

何か不足していますか?それとも、この nhibernate ルートを使用すると、多くのオーバーヘッドが発生しますか?

それ以外の場合は、コードのクリーンさが気に入っています。

protected void Page_Load(object sender, EventArgs e)
{
    ICustomerRepository repository = new CustomerRepository();
    Customer customer = repository.GetById(id);
}

public class CustomerRepository : ICustomerRepository
        {
            public Customer GetById(string Id)
            {
                using (ISession session = NHibernateHelper.OpenSession())
                {
                    Customer customer = session
                                        .CreateCriteria(typeof(Customer))
                                        .Add(Restrictions.Eq("ID", Id))
                                        .UniqueResult<Customer>();
                    return customer;
                }
            }
        }

私が従った例では、セッションを管理するのに役立つヘルパー クラスを作成しました。

public class NHibernateHelper
    {
        private static ISessionFactory _sessionFactory;
        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    Configuration cfg = new Configuration();
                    cfg.Configure();
                    cfg.AddAssembly(typeof(Customer).Assembly);
                    _sessionFactory = cfg.BuildSessionFactory();
                }
                return _sessionFactory;
            }

        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }

私が取り組んでいるアプリケーションでは、速度が重要です。そして最終的には、Web アプリとデータベースの間で大量のデータがやり取りされます。エージェントが顧客レコードを取得するのに 3 秒ではなく 1/3 秒かかる場合、それは大ヒットです。しかし、私が奇妙なことをしていて、これが 1 回限りの初期セットアップ コストである場合、パフォーマンスが DB でストアド プロシージャを実行するのと同じくらい優れていれば、それだけの価値があるかもしれません。

まだ提案を受け付けています!


更新しました。

ORM/NHibernate ルートを廃棄しています。パフォーマンスが遅すぎて、使用を正当化できないことがわかりました。基本的な顧客クエリは、私たちの環境では時間がかかりすぎます。1 秒未満の応答に比べて 3 秒は多すぎます。

遅いクエリが必要な場合は、現在の実装を維持します。それを書き直すという考えは、時間を大幅に増やすことでした。

しかし、先週 NHibernate で遊んだ後では、それは素晴らしいツールです! このプロジェクトの私のニーズにはまったく合いません。

4

4 に答える 4

6

あなたが持っている設定が今うまくいくなら、なぜそれを台無しにするのですか? そのままのコードで特定のニーズや問題を特定しているようには思えません。

正しい責任と役割が尊重されるように、多くの OO タイプが集まり、ここでさまざまなリファクタリングを提案する可能性があると確信しています。しかし、あなたが今持っているコードはシンプルで、何の問題もないように思えます - 私はそのままにしておくと思います.

于 2009-03-13T23:17:38.513 に答える
5

基本的にNHibernateが行うことを手動で行うことにより、DALレイヤーを実装しました。NHibernate が行うことは、Domain オブジェクトから継承する Proxy クラスを作成することです (そのすべてのフィールドが virtual としてマークされている必要があります)。すべてのデータ アクセス コードはプロパティ オーバーライドに入りますが、実際には非常に洗練されています。

リポジトリに単純なプロパティ自体を入力させ、遅延読み込み用のプロキシのみを使用することで、これをいくらか単純化しました。私が最終的に得たのは、次のような一連のクラスです。

public class Product {
  public int Id {get; set;}
  public int CustomerId { get; set;}
  public virtual Customer Customer { get; set;}
}
public class ProductLazyLoadProxy {
  ICustomerRepository _customerRepository;
  public ProductLazyLoadProxy(ICustomerRepository customerRepository) {
    _customerRepository = customerRepository;
  }
  public override Customer {
    get {
      if(base.Customer == null)
        Customer = _customerRepository.Get(CustomerId);
      return base.Customer
    }
    set { base.Customer = value; }
  }
}
public class ProductRepository : IProductRepository {
  public Product Get(int id) {
    var dr = GetDataReaderForId(id);
    return new ProductLazyLoadProxy() {
      Id = Convert.ToInt(dr["id"]),
      CustomerId = Convert.ToInt(dr["customer_id"]),
    }
  }
}

しかし、これらの約 20 を書いた後、私はあきらめて NHibernate を学びました。クエリには Linq2NHibernate を、構成には FluentNHibernate を使用するようになりました。

于 2009-03-13T23:34:53.103 に答える
2

これは過激すぎるかもしれませんし、問題の解決にもなりませんが、データレイヤーを完全に破棄して ORM を選択するのはどうでしょうか? DAL に 1 週​​間ほど費やすことで生じる多くのコードの冗長性を節約できます。

それはさておき、使用しているパターンはリポジトリ パターンに似ています。あなたの選択肢は

  • Email クラスのサービス オブジェクト (たとえば、EmailService) は、コンストラクタまたはプロパティでインスタンス化されます。email.Service.GetById(id) などのインスタンス経由でアクセス
  • 同様のアプローチである Email.GetById(id) のようなメールの静的メソッド
  • EmailManager.GetById(int) のような静的メソッドを持つ、EmailManager など、基本的にファサード クラスである完全に独立した静的クラス
  • email.Save() や email.GetById() などのインスタンスを扱う ActiveRecord パターン
于 2009-03-13T23:40:31.250 に答える
2

ほとんどの場合、アプリケーションにはトランザクション スクリプトでドメイン ロジックが設定されています。トランザクション スクリプトを使用する .NET 実装の場合、Martin Fowler は、テーブル データ ゲートウェイパターンの使用を推奨しています。テーブル データ ゲートウェイ パターンは、Microsoft が DataSet タイプのクラスで実装しているレコード セットに適しているため、.NET はこのパターンを適切にサポートします。

Visual Studio 環境内のさまざまなツールにより、生産性が向上します。DataSet はさまざまなコントロール (DataGridView など) に簡単にデータバインドできるため、データ駆動型アプリケーションに適しています。

ビジネス ロジックがいくつかの検証よりも複雑な場合は、ドメイン モデルが適切なオプションになります。ドメイン モデルには、まったく異なる一連のデータ アクセス要件が伴うことに注意してください。

于 2009-03-13T23:43:53.677 に答える