2017-03-23 10 views
1

すべてのCRUD操作がリポジトリで処理されるEF 6.0を使用する製品カタログMVC Webアプリケーションがあります。ここでは、ビューの1つは、CategoriesListと、の集計情報とそれに続くCategoryを示しています。これは、Categoryの横に、そのカテゴリの製品の総数が最小と最大の3つの列製品の価格。私は、ベーカリー製品のリポジトリEFリポジトリを使用した集計関数

unitOfWork.ProductRepository.Insert(new Product(){Name="Doughnut", Price=4.0, CategoryId=1}); 
unitOfWork.ProductRepository.Insert(new Product(){Name="Apple Pie", Price=7.0, CategoryId=1}); 
unitOfWork.ProductRepository.Insert(new Product(){Name="Meat Pie", Price=9.0, CategoryId=1}); 

私は

# Category  Total Products  Min Price  Max Price 
1 Bakery products 3      4    9 

を表示するビューを必要としている場合

public class Product 
{ 
    public string Name { get; set; } 
    public decimal Price { get; set; } 
    public int  CategoryId    { get; set; } 
    public virtual Category Category { get; set; } 
} 

public class Category 
{ 
    public string Name { get; set; } 
    public virtual ICollection<Product> Products { get; set; } 
} 

その後、私は出て処理するために明るい考えであることを信じていません。リポジトリを使用するというアイデアがすべて失われてしまい、AFAIKは悪い習慣として広く認識されています。
DbContextを直接利用するクエリを書くことができますが、このタイプのタスクが実際のアプリケーションでどのように処理されるかを知りたがっていますか? 新しいビューモデルが必要な場合があり、このデータを取得する別の読み取り専用リポジトリを追加する必要がありますか?このようなもの?

public class CategoryStatsVM 
{ 
    public string Name { get; set; } 
    public virtual ICollection<Product> Products { get; set; } 
    public int  Count { get; set; } 
    public decimal MinPrice { get; set; } 
    public decimal MaxPrice { get; set; } 
} 
+0

トランザクションファイルの最後のログを取得するには、このような集計関数を使用することができます:あなたは、もちろん一つの方法ですべてを持つことができますDbContext' **は**リポジトリとUOWであり、簡単にそのようなシナリオをサポートしています)、追加の抽象化(制限事項)から、あなたは 'entity-framework'タグを削除してください。 –

+0

@IvanStoev私はマイクロソフトの記事に従っていました。https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-リポジトリとUoWをEFの上に実装する方法を説明しているasp-net-mvcアプリケーションのリポジトリとユニットのパターン-a-asp-net-mvc-appですので、追加の抽象化が必要ですMicrosoftの文書に従うときに人々がこれらの問題にどのように対処するかを理解する。 – Jyrkka

答えて

0

私は、あなたが「それはリポジトリを使用して、すべてのアイデアを台無しにするので、私は、リポジトリの外にクエリを処理するための明るい考えであることを信じていない」の意味するものではよく分かりません。 リポジトリの背後にある主な考え方は、データアクセスを抽象化することです。何らかの集計や他の計算などを行いたい場合、それは主にビジネスロジックの一部です。 VMは、カウント、最大値、最小値を必要とするコンポーネントです。 VMは基本的に抽象ビューであり、ビューは通常ビジネス要件から導出されます。だから、私はこれらのクエリを行うことはデータアクセスの一部ではなく、リポジトリの一部ではないと思います。

public IQueryable<Category> GetById(int i) 
{ 
    return dbContext.Category.Single(c=>c.CategoryId==i); 
} 

そして、ビジネスロジックにあなたはこのようにそれを使用することができます: 私は何だろうと、このようなリポジトリのインターフェースにメソッドを追加することです

unitOfWork.CategoryRepository.GetById(3).Products.Count(); 
unitOfWork.CategoryRepository.GetById(3).Products.Min(p=>p.Price); 

これはまた、追加の利点を持っていますEntityへのLInQの遅延実行が失われないので、最小値の計算と検索はデータベース上で実行されます。

+0

あなたの洞察をお寄せいただきありがとうございますが、私が間違っていると思っています。私は 'Categories'のリストをグリッドに表示したいのですが、それを構築するために何十ものクエリを実行したくありません。また、IQueryable を返すと言ったことを理解することは、あなたが読むことができる悪い考えです。この記事http://codetunnel.io/should-you-return-iqueryablet-from-your-repositories/と他の多くのもの、ちょうどそれをgoogleしてください。しかし、再び、私はこれが正しいことであると言っているわけではありません。私はベストプラクティスに従えば、これがどのように達成されるべきかを理解しようとしています... – Jyrkka

+0

ブログの投稿をありがとう。私は必ずしも同意するとは限りませんが、他の意見を読むことは常に良いことです。 –

+0

本当にあなたに同意する、だから私はここで尋ねている。あなたの考えを分かち合うことができれば、私の制約を受け入れることができる何かを考えることができれば、感謝しています。 – Jyrkka

0

すでに@Ivan Stoevに言及されているように。 DbContextはリポジトリです。それはすべての基本的なCRUD操作を処理し、その上の別のリポジトリ層は重複しているようです。 「未加工」のデータをリポジトリと呼び、追加のロジックを適用し、プレゼンテーションレイヤーにデータを提供するビジネスレイヤーというより、サウンドのことを話しています。

だからあなたの場合には、あなたはサービス/ビジネス・ファクトリー/クラスを持っているでしょう - あなたはそれを呼ぶものは何でも - このような方法で: - あなたが必要があるのでそれがあります最後の関数について

public IEnumerable<CategoryStatsVM> GetCategoryStats() 
{ 
    IList<Category> categories = dbContext.Categories.Include(m => m.Products).ToList(); 

    foreach (Category category in categories) 
    { 
     yield return new CategoryStatsVM 
     { 
      Name = category.Name, 
      Count = category.Products.Count(), 
      Products = this.GetProducts(category.Products), 
      MinPrice = category.Products.Aggregate(GetMinPrice), 
      MaxPrice = category.Products.Aggregate(GetMaxPrice) 
     } 
    } 
} 

private Product GetMinPrice(Product min, Product current) 
{ 
    return min == null || curr.Price < min.Price ? curr : min; 
} 

private Product GetMaxPrice(Product max, Product current) 
{ 
    return max == null || curr.Price > max.Price ? curr : max; 
} 

private IEnumerable<ProductVM> GetProducts(IEnumerable<Product> products) 
{ 
    List<ProductVM> products; // create instance of the product view model list 
    return products; 
} 

ちょうど1ノート製品のビューモデルクラスも作成します。プレゼンテーション層のデータモデルで作業するべきではありません。

私はそれをより読みやすくするために、集約のための分離された機能を作成しました。`(これ

MinPrice = category.Products.Aggregate((min, curr) => min == null || curr.Price < min.Price ? curr : min), 
+0

このように 'IEnumerable'を使用すると、パフォーマンスが大幅に低下します。 'IQueryable'をSQLクエリに変換し、データベースが実行して数字だけを返すのではなく、すべてのカテゴリオブジェクトをメモリに読み込んでカウントします。 –

+0

メンバ型IEnumerableを使用しているだけでは、すべてのオブジェクトをメモリに読み込むわけではありません。 IQueryableもIEnumerableから継承します。変数定義はコードの実行に影響しません。これは、メモリー内のオブジェクトを使用して作業するか、オブジェクトが必要なときにデータベース呼び出しを行うかを決定する問合せで行います。これは、メモリ内のすべてをロードするGetCategoryStatsの最初の行である.ToList()メソッドです。それがこの方法で良いかどうかは、他のロジック、データベース構造、アイテム数などに依存しますが、IEnumerableはそれとは関係ありません。 – Tacud

+0

私は明確ではなかったと思いますが、私はあなたが「IEnumerable __like this__を使用すると」と言ったことを正確に意味していました。私はもっ​​と明確にすべきだったし、私も 'ToList()'を意味すると付け加えるべきだった。そして、この方法では、使用するコンポーネントに制御を提供して、実行するタイミングを決めることはありません。 IQueryableとクエリ自体を残しておくと、重要な機能であるクエリの実行や合成を制御するオプションが残されます。 –

0

あなたはUserLogsあなたの問題は、EFによって引き起こされていない

UsersLogs.Where(i => i.Id== _id).Max(x => x.transId) 
関連する問題