1

UserRepository などのリポジトリがあります。指定された userId でユーザーを返します。私は Web アプリケーションで作業しているため、オブジェクトはメモリにロードされ、使用され、リクエストが終了すると破棄されます。

これまで、リポジトリを作成するときは、データベースからデータを取得するだけでした。取得した User オブジェクトをメモリに保存しません (つまり、リポジトリのコレクションに保存します)。リポジトリの GetById() メソッドが呼び出されるとき、オブジェクトが既にコレクションにあるかどうかを確認しません。データベースにクエリを実行するだけです。

私の質問は

  1. 取得したオブジェクトをメモリに保存する必要がありますか? また、リポジトリの Get メソッドが呼び出されたときに、データベースを呼び出す前に、オブジェクトがメモリに存在するかどうかを最初に確認する必要がありますか?
  2. または、Web リクエストは短命のセッションであり、すべてのオブジェクトは後で破棄されるため、メモリ コレクションは不要ですか。
4

3 に答える 3

3

1) 取得したオブジェクトをメモリに保存する必要がありますか? また、リポジトリの Get メソッドが呼び出されたときに、データベースを呼び出す前に、まずオブジェクトがメモリに存在するかどうかを確認する必要がありますか?

リポジトリは、メモリ内コレクションの目的をシミュレートするのに十分なほど抽象化する必要があるため、それは本当にあなた次第であり、ユースケース次第だと思います.

データベースから取得した後にオブジェクトを保存すると、いわゆる の実装になる可能性がありますIdentityMap。これを行うと、非常に複雑になる可能性があります (ドメインによって異なります)。

依存するインフラストラクチャ層に応じて、ORM が提供する IdentityMap があればそれを使用できます。

しかし、本当の問題は、IdentityMap を実装する価値があるかどうかです。

つまり、クエリを繰り返すことは、パフォーマンスと整合性の 2 つの理由から間違っている可能性があることに同意します。Martin Fowler の引用を次に示します。

古いことわざに、時計を 2 つ持っている人は今が何時か分からないというものがあります。2 つのウォッチが紛らわしい場合は、データベースからオブジェクトをロードする際にさらに大きな混乱が生じる可能性があります。

しかし、時には実用的で、必要なときにロードする必要がある場合もあります。

2)または、Webリクエストは短命のセッションであり、すべてのオブジェクトは後で破棄されるため、メモリコレクションは不要ですか

たとえば、場合によっては、別の場所でオブジェクトをいじる必要がある場合があります。その場合、価値があるかもしれませんが、データベースからユーザーをロードしてユーザー セッション ID を更新する必要があるとします。リクエスト全体で一度だけ行う場合があります。

于 2013-07-19T09:01:54.237 に答える
1

Entity Framework や NHibernate などの ORM を使用している場合、既に処理されています。すべての読み取りエンティティは IdentityMap メカニズムを介して追跡され、キー (EF では DbSet.Find) による検索は、エンティティが既に読み込まれている場合はデータベースにヒットしません。 .

データベースへの直接アクセスまたは microORM をリポジトリのベースとして使用している場合は、注意が必要です。IdentityMap を使用しないと、基本的に値オブジェクトを操作することになります。

using System;
using System.Collections.Generic;
using System.Linq;

namespace test
{
internal class Program
{
    static void Main()
    {
        Console.WriteLine("Identity map");
        var artrepo1 = new ArticleIMRepository();
        var o1 = new Order();
        o1.OrderLines.Add(new OrderLine {Article = artrepo1.GetById(1, "a1", 100), Quantity = 50});
        o1.OrderLines.Add(new OrderLine {Article = artrepo1.GetById(1, "a1", 100), Quantity = 30});
        o1.OrderLines.Add(new OrderLine {Article = artrepo1.GetById(2, "a2", 100), Quantity = 20});
        o1.ConfirmOrder();
        o1.PrintChangedStock();
        /*
        Art. 1/a1, Stock: 20
        Art. 2/a2, Stock: 80
        */

        Console.WriteLine("Value objects");
        var artrepo2 = new ArticleVORepository();
        var o2 = new Order();
        o2.OrderLines.Add(new OrderLine {Article = artrepo2.GetById(1, "a1", 100), Quantity = 50});
        o2.OrderLines.Add(new OrderLine {Article = artrepo2.GetById(1, "a1", 100), Quantity = 30});
        o2.OrderLines.Add(new OrderLine {Article = artrepo2.GetById(2, "a2", 100), Quantity = 20});
        o2.ConfirmOrder();
        o2.PrintChangedStock();
        /*
        Art. 1/a1, Stock: 50
        Art. 1/a1, Stock: 70
        Art. 2/a2, Stock: 80
        */
        Console.ReadLine();
    }
    #region "Domain Model"
    public class Order
    {
        public List<OrderLine> OrderLines = new List<OrderLine>();

        public void ConfirmOrder()
        {
            foreach (OrderLine line in OrderLines)
            {
                line.Article.Stock -= line.Quantity;
            }
        }

        public void PrintChangedStock()
        {
            foreach (var a in OrderLines.Select(x => x.Article).Distinct())
            {
                Console.WriteLine("Art. {0}/{1}, Stock: {2}", a.Id, a.Name, a.Stock);
            }
        }
    }

    public class OrderLine
    {
        public Article Article;
        public int Quantity;
    }

    public class Article
    {
        public int Id;
        public string Name;
        public int Stock;
    }
    #endregion

    #region Repositories
    public class ArticleIMRepository
    {
        private static readonly Dictionary<int, Article> Articles = new Dictionary<int, Article>();

        public Article GetById(int id, string name, int stock)
        {
            if (!Articles.ContainsKey(id))
                Articles.Add(id, new Article {Id = id, Name = name, Stock = stock});
            return Articles[id];
        }
    }

    public class ArticleVORepository
    {
        public Article GetById(int id, string name, int stock)
        {
            return new Article {Id = id, Name = name, Stock = stock};
        }
    }
    #endregion
}
}
于 2013-07-19T19:52:55.350 に答える
1

いつものように、「フリーサイズ」はないと思います。

データが頻繁に取得される場合、データがすぐに古くならない場合、または単純に効率化のために、リポジトリにキャッシュの形式を実装する場合があります。

ただし、必要に応じてリポジトリをラップできる汎用キャッシュ デコレータを実装することもできます。

したがって、各ユースケースをメリットに基づいて使用する必要があります。

于 2013-07-19T12:15:00.347 に答える