![](/img/trans.png)
[英]What interface should my service return? IQueryable, IList, IEnumerable?
[英]Which types should my Entity Framework repository and service layer methods return: List, IEnumerable, IQueryable?
我有一個具體的存儲庫實現,它返回實體的IQueryable:
public class Repository
{
private AppDbContext context;
public Repository()
{
context = new AppDbContext();
}
public IQueryable<Post> GetPosts()
{
return context.Posts;
}
}
然后,我的服務層可以根據其他方法(其中,分頁等)的需要執行LINQ
現在我的服務層設置為返回IEnumerable:
public IEnumerable<Post> GetPageOfPosts(int pageNumber, int pageSize)
{
Repository postRepo = new Repository();
var posts = (from p in postRepo.GetPosts() //this is IQueryable
orderby p.PostDate descending
select p)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize);
return posts;
}
這意味着在我的代碼隱藏中,如果我想綁定到轉發器或其他控件,我必須執行ToList()。
這是處理返回類型的最佳方法,還是在從服務層方法返回之前需要轉換為列表?
這兩種方法都是可能的,這只是選擇的問題。
一旦你使用了IQueryable
你就擁有了一個簡單的存儲庫,它可以在大多數情況下工作,但它更容易測試,因為在IQueryable
上定義的查詢是linq-to-entities。 如果您模擬存儲庫,它們是單元測試中的linq-to-objects =您不測試您的實際實現。 您需要集成測試來測試查詢邏輯。
一旦使用IEnumerable
您將擁有非常復雜的存儲庫公共接口 - 對於需要在存儲庫中公開特殊查詢的每個實體,您將需要特殊的存儲庫類型。 這種存儲庫在存儲過程中更常見 - 存儲庫中的每個方法都映射到單個存儲過程。 這種類型的存儲庫提供了更好的關注點分離和更少的漏洞抽象,但同時它消除了大量的ORM和Linq靈活性。
對於最后一個,您可以使用組合方法,其中您有方法返回IEnumerable用於大多數常見方案(更頻繁地使用查詢)和一個方法公開IQueryable
用於罕見或復雜的動態構建查詢。
編輯:
正如使用IQueryable
評論中所述,有一些副作用。 當你暴露IQueryable
你必須保持你的上下文活着,直到你執行查詢 - IQueryable
以與IEnumerable
相同的方式使用延遲執行,所以除非你調用ToList
, First
或其他執行查詢的函數,你仍然需要你的上下文存活。
實現這一目標的最簡單方法是在存儲庫中使用一次性模式 - 在其構造函數中創建上下文,並在存儲庫處置時進行處置。 然后你可以使用using
塊,並執行它們內部查詢。 此方法適用於非常簡單的場景,您可以對每個存儲庫的單個上下文感到滿意。 更復雜(和常見)的場景需要在多個存儲庫之間共享上下文。 在這種情況下,您可以使用上下文提供程序/工廠(一次性)之類的東西,並將工廠注入存儲庫構造函數(或允許提供程序創建存儲庫)。 這導致DAL層工廠和定制工作單元。
您的問題的另一個詞似乎需要確定何時處置AppDbContext
或它在何處。
如果你不處理它,意味着它在應用程序退出時被處理掉,那么返回IEnumerable / IQueryable沒有問題,沒有實際數據。 但是,在放置AppDbContext
之前,您需要將類型作為IList返回,並具有實際數據。
更新:我認為你需要捕獲以下代碼含義,盡管你已經知道了。
//outside of this code is refered to your code.
//Returning IEnumerable could be used outside this scope if AppDbContext is ensured no disposing
public IEnumerable<Post> GetIEnumerableWithoutActualData()
{
return context.Posts;
}
//Even if AppDbContext is disposed, IEnumerable could be used.
public IEnumerable<Post> GetIEnumerableWithActualData()
{
return context.Posts.ToList();
}
您的返回類型應始終盡可能高於繼承層次結構( 或者如果基礎位於底部,我應該將其寫為低 )。 如果您的所有方法都需要IQueryable<T>
,那么所有返回值都應該放棄該類型。
也就是說, IEnumerable<T>
有一個方法( AsQueryable()
),你可以調用它來實現(我相信)所需的結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.