3

これは、ここでの私の質問に関連しています (ただし、かなり独立しています): Why SELECT N + 1 with no external keys and LINQ?

DataLoadOptions熱心な読み込みを強制するために使用しようとしましたが、うまくいきません。

私は手動で LinqToSQL マッピングを作成しており、最初はこのチュートリアルに従っていました: http://www.codeproject.com/Articles/43025/A-LINQ-Tutorial-Mapping-Tables-to-Objects

今、私はこのチュートリアルを見つけました: http://msdn.microsoft.com/en-us/library/bb386950.aspx

私が見つけられる大きな違いが少なくとも 1 つあります。ICollection最初のチュートリアルでは、 と 2 番目の を返すことを提案していEntitySetます。問題が発生したため、コードを return に切り替えようとしEntitySetましたが、ビューとコントローラーで System.Data.Linq を参照する必要があるという問題が発生しました。私はそれをやろうとしましたが、うまくいきませんでした。また、それが良い考えかどうかもわかりません。

この時点で、適切な設計のためにどの戻り値の型を使用する必要があるかを知りたいだけですか? 優れた設計で、特定のケースで熱心な読み込みを強制することはできますか?

4

1 に答える 1

1

試行錯誤の末、最終的には解決策にたどり着きます。ICollectionor IList、または場合によってはを返しても問題ありませんIEnumerableEntitySet戻る、または悪い考えだと考える人もIQueryableいますが、データソース/テクノロジーの多くにさらされるため、私は同意します。戻ることIEnumerableは悪い考えであり、それは依存しているようです。問題は、遅延読み込みに使用できることです。これは良いことかもしれませんし、そうでないかもしれません。

繰り返し発生する問題の 1 つは、ページ外の合計アイテム数を含むページ化された結果を返すことです。CollectionPage<T>これは、 ( http://www.codetunnel.com/blog/post/104/how-to-properly-return-a-paged-result-set-from-your-repository )を作成することで解決できます。

ここでリポジトリから何を返すかについての詳細:

http://www.codetunnel.com/blog/post/103/should-you-return-iqueryablet-from-your-repositories

http://www.shawnmclean.com/blog/2011/06/iqueryable-vs-ienumerable-in-the-repository-pattern/

ビジネス ロジックまたは DAL の戻り値の型に対する IEnumerable と IQueryable の比較

List、IList、IEnumerable、IQueryable、ICollection、最も柔軟な戻り値の型はどれ?

さらに重要なのは、熱心な読み込みを実行DataLoadOptions できることです! コードを大幅に再構築したので、何が間違っていたのかが 100% わかりませDataLoadOptionsん。私が収集した限りでは、使用DataContext後にに追加しようとすると例外が発生するはずですが、DataContextそうではありませんでした。私が見つけたのは、作業単位パターンで考えることです。ただし、私のニーズのために(また、戻りたくないため、EntitySetまたはIQueryable私のリポジトリから) リポジトリ間の作業単位を実装するつもりはありません。代わりに、リポジトリ メソッドを独自の小さな作業単位として考えているだけです。これには悪い点があると確信しており (たとえば、一部の更新シナリオではデータベースへのラウンドトリップが増える可能性があります)、将来的には再考する可能性があります。ただし、これは単純でクリーンなソリューションです。

詳細はこちら:

https://stackoverflow.com/a/7941017/1312533

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net- mvc-アプリケーション

これは、私のリポジトリで最終的に得られたものです。

public class SqlLocalizedCategoriesRepository : ILocalizedCategoriesRepository
{
    private string connectionString;
    private HttpContextBase httpContext;
    public SqlLocalizedCategoriesRepository(string connectionString, HttpContextBase httpContext) // Injected with Inversion of Control
    {
        this.connectionString = connectionString;
        this.httpContext = httpContext;
    }

    public CollectionPage<Product> GetProductsByLocalizedCategory(string category, int countryId, int page, int pageSize)
    {
        // Setup a DataContext
        using (var context = new DataContext(connectionString)) // Because DataContext implements IDisposable it should be disposed of
        {
            var dlo = new System.Data.Linq.DataLoadOptions();
            dlo.LoadWith<Product>(p => p.ProductSubs); // In this case I want all ProductSubs for the Products, so I eager load them with LoadWith. There's also AssociateWith which can filter what is eager loaded.
            context.LoadOptions = dlo;
            context.Log = (StringWriter)httpContext.Items["linqToSqlLog"]; // For logging queries, a must so you can see what LINQ to SQL generates

            // Query the DataContext
            var cat = (from lc in context.GetTable<LocalizedCategory>()
                       where lc.CountryID == countryId && lc.Name == category
                       select lc.Category).First(); // Gets the category into memory. Might be some way to not get it into memory by combining with the next query, but in my case my next step is that I'm also going to need the Category anyway so it's not worth doing because I'm going to restructure this code to take a categoryId parameter instead of the category parameter.

            var products = (from p in context.GetTable<Product>()
                            where p.ProductCategories.Any(pm => pm.Category.CategoryID == cat.CategoryID)
                            select p); // Generates a single query to get the the relevant products, which with DataLoadOptions loads related ProductSubs. It's important that this is just a query and not loaded into memory since we're going to split it into pages.

            // Return the results
            var pageOfItems = new CollectionPage<Product>
            {
                Items = products.Skip(pageSize * (page - 1)).Take(pageSize).ToList(), // Gets the page of products into memory
                TotalItems = products.Count(), // Get to total count of items belonging to the Category
                CurrentPage = page
            };
            return pageOfItems;
        }
    }
}
于 2012-10-04T06:05:33.050 に答える