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();
}
}