1、使用AsNoTracking()
使用AsNoTracking()後,將不監聽對象的狀態(是否被改變);當確定查詢出來的數據不會改變的時候使用AsNoTracking();
使用context.Entry<User>(user).State 查看對象監聽狀態。
2、正確使用Find(id=10)來代替FirstOrDefault(t=>t.id=10)
Find會優先查詢緩存,當前面已經查詢過這條數據的時候使用,而FirstOrDefault每次都會查詢數據庫;
當id=10的數據被修改之後,find查出的數據是新數據。
3、正確使用延遲查詢(延遲加載)
使用延遲加載可以疊加多次查詢條件,一次性提交給數據庫,可以按需獲取數據。
3.1 使用ToList()的時候會立馬執行數據庫sql查詢,看到過很多同學先ToList()再Where()過濾。
其它的還有:Count() 、FirstOrDefault()、迭代器foreach。等都會立刻執行sql。
3.2 迭代(如foreach)使用延遲查詢的時候,迭代完了才關閉鏈接,應當避免使用這種場景。可以在迭代之前ToList()。
3.3 延遲加載的對象(IQueryable<T>)脫離了DbContext上下文對象的範圍後不能被查詢,因爲DbContext被釋放了。
4、正確區分IQueryable和IEnumerable
4.1 IEnumerable(linq to object)用於操作內存對象。是個迭代器的實現。
Where(t=>t.id>10)中的“t=>t.id>10”是個委託
4.2 IQueryable(linq to sql)用於操作數據庫,且繼承了IEnumerable。 IQueryable中實現了表達式目錄樹(Expression),IQueryProvider根據表達式目錄樹來構建sql語句。
Where(t=>t.id>10)中的“t=>t.id>10”是個表達式目錄樹
5、正確使用導航屬性
在主表對象中包含一個子表集合對象的屬性就是導航屬性。跟數據庫中的主外鍵設置無關。
5.1 導航屬性要延遲加載必須具備兩個條件:
a、導航屬性是virtual的;
b、延遲查詢必須是開啓的。context.Configuration.LazyLoadingEnabled=true; (默認就是true的)
5.2 延遲查詢關閉之後可以使用顯示加載的方式:
加載集合: context.Entry<Company>(company).Collection(t=>t.Users).Load();
加載單個: context.Entry<Company>(company).Reference(t=>t.Users).Load();
6、預先加載
使用Include,查詢主表時把子表(導航屬性)也一次性查出來。延遲查詢關閉後也不影響的。
例如:context.Set<Company>().Include("Users").Where(t=>t.id<10);
7、使用TransactionScope
TransactionScope可以完成多個context多個SaveChange的事務問題,默認一個SaveChange是一個事務
TransactionScope可以用來做分佈式事務。
還可以使用context.Database.BeginTransaction做單庫事務。
using (DbContext context = new DbContext())
{
using (TransactionScope tran = new TransactionScope())
{
context.SaveChange();
context.SaveChange();
//無異常會執行Complete 提交事務
tran.Complete();
}
}