試行錯誤の末、最終的には解決策にたどり着きます。ICollection
or IList
、または場合によってはを返しても問題ありませんIEnumerable
。EntitySet
戻る、または悪い考えだと考える人も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;
}
}
}