簡體   English   中英

我的Entity Framework存儲庫和服務層方法應該返回哪些類型:List,IEnumerable,IQueryable?

[英]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相同的方式使用延遲執行,所以除非你調用ToListFirst或其他執行查詢的函數,你仍然需要你的上下文存活。

實現這一目標的最簡單方法是在存儲庫中使用一次性模式 - 在其構造函數中創建上下文,並在存儲庫處置時進行處置。 然后你可以使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM