EF(EFCore)性能優化與高級用法

1、使用AsNoTracking()

使用AsNoTracking()後,將不監聽對象的狀態(是否被改變);當確定查詢出來的數據不會改變的時候使用AsNoTracking();

使用context.Entry<User>(user).State 查看對象監聽狀態。

2、正確使用Find(id=10)來代替FirstOrDefault(t=>t.id=10)

Find會優先查詢緩存,當前面已經查詢過這條數據的時候使用,而FirstOrDefault每次都會查詢數據庫;當id=10的數據被修改之後,find查出的數據是新數據。

3、正確區分IQueryable和IEnumerable

3.1 IEnumerable(linq to object)用於操作內存對象。是個迭代器的實現。

      3.1.1 Where(t=>t.id>10)中的“t=>t.id>10”是個委託

      3.1.2 封裝的函數的時候將返回值設爲IEnumerable<T>,即使返回return IQueryable<T>也會立刻查詢數據庫

3.2 IQueryable(linq to sql)用於操作數據庫,且繼承了IEnumerable。 IQueryable中實現了表達式目錄樹(Expression),IQueryProvider根據表達式目錄樹來構建sql語句。

      3.2.1 Where(t=>t.id>10)中的“t=>t.id>10”是個表達式目錄樹

      3.2.2 AsEnumerable() 和 AsQueryable()如果後面不繼續跟過濾條件等,效果是一樣的。 如果後面加了Where / Select / Take() /Skip 等條件,AsEnumerable()先查數據庫再過濾,AsQueryable()將條件生成sql,一起在數據庫中過濾。

4、正確使用導航屬性 和 延遲查詢(延遲加載)

在主表對象中包含一個子表集合對象的屬性就是導航屬性。跟數據庫中的主外鍵設置無關。

利用延遲加載可以疊加多次查詢條件,一次性提交給數據庫。

使用建議:在開發中不確定後面是否需要關聯表數據,可以使用延遲加載來按需獲取數據。

4.1 導航屬性要延遲加載必須具備兩個條件:

        a、導航屬性是virtual的;

        b、延遲查詢必須是開啓的。

            EF:context.Configuration.LazyLoadingEnabled=true; (默認就是true的)

            EF Core: 

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    if (!optionsBuilder.IsConfigured)
        var builder = optionsBuilder.UseSqlServer(_connStr);

    optionsBuilder.UseLazyLoadingProxies(); //啓用延遲加載

}

4.2  延遲查詢關閉之後可以使用顯示加載的方式:

      加載集合: context.Entry<Company>(company).Collection(t=>t.Users).Load();     

      加載單個: context.Entry<Company>(company).Reference(t=>t.Users).Load();

4.3 使用ToList()的時候會立馬執行數據庫sql查詢,看到過很多同學先ToList()再Where()過濾。

        其它的還有:Count() 、FirstOrDefault()、迭代器IEnumerable/foreach 等都會立刻執行sql。

        封裝函數的時候可以返回IQueryable<T>,而不是IEnumable<T>,防止立馬查詢數據庫。

4.4 迭代(如foreach)使用延遲查詢的時候,迭代完了才關閉鏈接,應當避免使用這種場景。可以在迭代之前ToList()。

4.6 延遲加載的對象(IQueryable<T>)脫離了DbContext上下文對象的範圍後不能被查詢,因爲DbContext被釋放了。

5、預先加載

使用Include,查詢主表時把子表(導航屬性)也一次性查出來。延遲查詢關閉後也不影響的。

例如:context.Set<Company>().Include("Users").Where(t=>t.id<10);

使用建議:當開發中能確定後面一定會用到子表數據的時候可以使用預先加載。

6、使用TransactionScope

TransactionScope可以完成多個context多個SaveChange的事務問題,默認一個SaveChange是一個事務

還可以使用context.Database.BeginTransaction做單庫事務。

using (DbContext context = new DbContext())
{
    using (TransactionScope tran = new TransactionScope())
    {
        context.SaveChange();
        context.SaveChange();
        //無異常會執行Complete 提交事務
        tran.Complete();
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章