4

職場で、レガシーなエンタープライズ アプリケーションの開発に取り掛かりましたが、それはまだ生産中であり、設計の悪さと不安定さのためにここ数か月停止しています。

そこで、EF5 の使用を開始し、いくつかの設計パターン/レイヤーをアプリケーションに適用しました。

私が理解するのに苦労しているのは、サービス層が私たちの場合に正確に何をすべきかということです. それは過剰なアーキテクチャになるのでしょうか、それとも不必要な複雑さを追加せずにいくつかの利点を提供するでしょうか?

これまでに得たものをお見せしましょう:

  • レガシーデータベースをマッピングするためにEF(POCOを使用したコードファースト)を導入しました(かなりうまく機能します)
  • 新しいデータレイヤーで必要なほとんどのもののリポジトリを作成しました(特定の実装、一般的なリポジトリを使用した懸念の分離に関する利点は見られません..)

ここで、特定のケースでは、記事の価格を計算することについてです-arcile から直接、または記事が含まれるグループから価格を取得します (価格が指定されていない場合)。さまざまな価格表 (注文の完全な値に応じて) や、特別価格などを設定できる顧客に応じて、さまざまな価格表が関係するため、より複雑になっています。

だから私の主な質問は、正しい価格を得る責任があるのは誰ですか?

私の考えは次のとおりです。注文は、構成されているアイテムを知っている必要があります。一方、これらのアイテムは価格を知る必要がありますが、注文はアイテムの価格を計算する方法を知っている必要はありません。コストを要約する必要があるだけです。

現時点での私のコードの抜粋:

ArticlePrice (POCO、マッピングはまもなく Fluid API に置き換えられます)

[Table("artikeldaten_preise")]
public class ArticlePrice : BaseEntity
{
    [Key]
    [Column("id")]
    public int Id { get; set; }

    [Column("einheit")]
    public int UnitId { get; set; }

    [ForeignKey("UnitId")]
    public virtual Unit Unit { get; set; }

    [Column("preisliste")]
    public int PricelistId { get; set; }

    [ForeignKey("PricelistId")]
    public virtual Pricelist Pricelist { get; set; }

    [Column("artikel")]
    public int ArticleId { get; set; }

    [ForeignKey("ArticleId")]
    public virtual Article Article { get; set; }

    public PriceInfo PriceInfo { get; set; }

}

記事の価格リポジトリ:

   public class ArticlePriceRepository : CarpetFiveRepository
{
    public ArticlePriceRepository(CarpetFiveContext context) : base(context) {}

    public IEnumerable<ArticlePrice> FindByCriteria(ArticlePriceCriteria criteria)
    {
        var prices = from price in DbContext.ArticlePrices
                     where
                         price.PricelistId == criteria.Pricelist.Id
                         && price.ArticleId == criteria.Article.Id
                         && price.UnitId == criteria.Unit.Id
                         && price.Deleted == false
                     select price;

        return prices.ToList();
    }
}

public class ArticlePriceCriteria
{
    public Pricelist Pricelist { get; set; }
    public Article Article { get; set; }
    public Unit Unit { get; set; }

    public ArticlePriceCriteria(Pricelist pricelist, Article article, Unit unit)
    {
        Pricelist = pricelist;
        Article = article;
        Unit = unit;
    }
}

PriceService (恐ろしいコードの匂いがします... )

public class PriceService
{
    private PricelistRepository _pricelistRepository;
    private ArticlePriceRepository _articlePriceRepository;
    private PriceGroupRepository _priceGroupRepository;

    public PriceService(PricelistRepository pricelistRepository, ArticlePriceRepository articlePriceRepository, PriceGroupRepository priceGroupRepository)
    {
        _pricelistRepository = pricelistRepository;
        _articlePriceRepository = articlePriceRepository;
        _priceGroupRepository = priceGroupRepository;
    }

    public double GetByArticle(Article article, Unit unit, double amount = 1, double orderValue = 0, DateTime dateTime = new DateTime())
    {
        var pricelists = _pricelistRepository.FindByDate(dateTime, orderValue);

        var articlePrices = new List<ArticlePrice>();

        foreach (var list in pricelists)
            articlePrices.AddRange(_articlePriceRepository.FindByCriteria(new ArticlePriceCriteria(list, article, unit)));

        double price = 0;
        double priceDiff = 0;

        foreach (var articlePrice in articlePrices)
        {
            switch (articlePrice.PriceInfo.Type)
            {
                    case PriceTypes.Absolute:
                        price = articlePrice.PriceInfo.Price;
                        break;
                    case PriceTypes.Difference:
                        priceDiff = priceDiff + articlePrice.PriceInfo.Price;
                    break;
            }
        }

        return (price + priceDiff) * amount;
    }

    public double GetByPriceGroup(PriceGroup priceGroup, Unit unit)
    {
        throw new NotImplementedException("not implemented yet");
    }

    //etc. you'll get the point that this approach might be completely WRONG

}

私の最後の質問は次のとおりです。問題を正しくモデル化するにはどうすればよいですか? 自分のコードをオーバーアーキテクチャにしようとしているというのは正しいですか? 私のサービス層はどのように正しく見えますか? ArticlePriceService や ArticleGroupPriceService などを使用した方がよいでしょうか? しかし、誰がそのピースをつなぎ合わせて正しい価格を計算するのでしょうか? たとえば、「GetPrice」メソッドを持つ OrderItemService の責任でしょうか。しかし、やはり orderItemService は他のサービスについて知る必要があります..

アーキテクチャに関する可能な解決策と、どのオブジェクト/レイヤーが何をするかを教えてください。

さらに情報が必要な場合は、お気軽に追加の質問をしてください!

4

2 に答える 2

0

リポジトリ自体で十分な簡単なシナリオを提示しました。
もっとリポジトリがありますか?
アプリケーションが成長し、より多くのリポジトリが使用されることを期待していますか?

データ層を抽象化するサービス層を持つことは推奨されており、私が見たほとんどのアプリケーション/例で使用されており、オーバーヘッドはそれほど重要ではありません。

サービスを使用する理由の 1 つは、複数の異なるリポジトリからデータを取得し、データに対して何らかの集計や操作を実行する場合に考えられます。
サービス層は操作ロジックを提供しますが、サービスの消費者はいくつかの異なるリポジトリを処理する必要はありません。
また、1 つのトランザクションで複数のエンティティを変更し (意味 - 複数のリポジトリ)、すべての更新アクションが成功した場合にのみ変更を DB に保存する状況も考慮する必要があります。
そのような状況はUnit Of Work Patternを使用することを意味するはずであり、適切な単体テストを可能にするために、おそらくサービス層の使用を結論付けるでしょう。

于 2013-06-13T13:48:53.850 に答える