LINQ to SQL系列三 使用DeferredLoadingEnabled,DataLoadOption指定載入選項

來源:互聯網
上載者:User

本文中舉例用到的資料模型如下:

Student和Class之間是多對一關聯性,Student和Course之間是多對多關係。

DataContext的DeferredLoadingEnabled屬性指定是否需要延時載入,其預設值為true。以Student為例,其延時載入的對象是指Class和對應的Course。設定延時載入為true時,當訪問到Student執行個體的Class屬性或者StudentCourse屬性時會自動載入Class表和StudentCourse表中的資料,如下範例程式碼:

static void Main(string[] args){    using (var writer = new StreamWriter(WatchSqlPath, false, Encoding.UTF8))    {        using (DbAppDataContext db = new DbAppDataContext())        {            db.Log = writer;            //設定延時載入屬性為true            db.DeferredLoadingEnabled = true;            //獲得一個Student            var aStudent = db.Students.First();            //直接存取Student的Class屬性ClassName            Console.WriteLine("{0}屬於{1}",aStudent.Name ,aStudent.Class.ClassName);        }    }    Console.ReadLine();}

當設定DataContext的DeferredLoadingEnabled屬性為true時,可以直接存取關係表中的資料,我們可以看下以上代碼使用到的SQL語句:

SELECT TOP (1) [t0].[StudentID], [t0].[Name], [t0].[Hometown], [t0].[Gender], [t0].[Birthday], [t0].[ClassID], [t0].[WeightInKg], [t0].[HeightInCm], [t0].[Desc] AS [Desc]FROM [dbo].[Student] AS [t0]-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 4.0.30319.1SELECT [t0].[ClassID], [t0].[ClassName]FROM [dbo].[Class] AS [t0]WHERE [t0].[ClassID] = @p0-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [1]-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 4.0.30319.1

用到了兩個sql語句,在我們訪問到Student的Class屬性時,DataContext自動去載入了Class的資料。

在有些時候可以將DeferredLoadingEnabled屬性設定為false,設定為false時再直接存取Student的Class屬性時將拋出Null 參考的異常。

有了延時載入,LoadWith方法是做什麼用的呢?

MSDN上對LoadWith的解釋是:通過使用 lambda 運算式檢索與主目標相關的指定資料。

LoadWith不是DataContext的方法,而是DataLoadOptions的方法,可以給DataContext設定LoadOptions屬性來改變DataContext載入資料的方式;換句話說是LoadOptions設定是否在select主表資料時同時用join載入關聯表的資料。

假定情境:我希望在select Student表的資料時同時用一個sql將其class的屬性select出來,如下代碼:

static void Main(string[] args){    using (var writer = new StreamWriter(WatchSqlPath, false, Encoding.UTF8))    {        using (DbAppDataContext db = new DbAppDataContext())        {            db.Log = writer;            //聲明DataLoadOptions變數            var loadOptions = new DataLoadOptions();            //設定需要在load Student時需要同時load什麼            loadOptions.LoadWith<Student>(s=>s.Class);            //將DataLoadOptions執行個體賦值給db.LoadOptions            db.LoadOptions = loadOptions;            //載入一個Student            var student = db.Students.First();            Console.WriteLine("{0}屬於{1}",student.Name,student.Class.ClassName);        }    }    Console.ReadLine();}

其效果和上面例子完全一樣,但是執行的SQL卻是不一樣的,我們看下SQL:

SELECT TOP (1) [t0].[StudentID], [t0].[Name], [t0].[Hometown], [t0].[Gender], [t0].[Birthday], [t0].[ClassID], [t0].[WeightInKg], [t0].[HeightInCm], [t0].[Desc] AS [Desc], [t1].[ClassID] AS [ClassID2], [t1].[ClassName]FROM [dbo].[Student] AS [t0]INNER JOIN [dbo].[Class] AS [t1] ON [t1].[ClassID] = [t0].[ClassID]-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 4.0.30319.1

這次執行只用了一個SQL語句,Student表inner join Class表,這就是LoadWith的意義所在。

LoadWith可以用一個sql語句載入相關表的資料,那麼AssociateWith 方法又是做什麼用的呢?

還是假定一個情境,我們想知道某個班級的資訊和這個班級中體重大於30公斤的學生的資訊,也就是說在取得關聯表資料時附加了條件,請看下面的代碼及注釋:

static void Main(string[] args){    using (var writer = new StreamWriter(WatchSqlPath, false, Encoding.UTF8))    {        using (DbAppDataContext db = new DbAppDataContext())        {            db.Log = writer;            var loadOptions = new DataLoadOptions();            //在載入Class的Students屬性時附加上體重大於30的條件            loadOptions.AssociateWith<Class>(c => c.Students.Where(s => s.WeightInKg > 30));            db.LoadOptions = loadOptions;            //將DataLoadOptions執行個體賦值給db.LoadOptions            db.LoadOptions = loadOptions;            //取得id為1的班級            var aClass = db.Classes.Where(c=>c.ClassID == 1).Single();            Console.WriteLine("{0}體重大於30kg的同學有:",aClass.ClassName);            foreach (var item in aClass.Students)            {                Console.WriteLine("\t{0}",item.Name);            }        }    }    Console.ReadLine();}

同樣看下代碼執行的真實SQL語句:

SELECT [t0].[ClassID], [t0].[ClassName]FROM [dbo].[Class] AS [t0]WHERE [t0].[ClassID] = @p0-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [1]-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 4.0.30319.1SELECT [t0].[StudentID], [t0].[Name], [t0].[Hometown], [t0].[Gender], [t0].[Birthday], [t0].[ClassID], [t0].[WeightInKg], [t0].[HeightInCm], [t0].[Desc] AS [Desc]FROM [dbo].[Student] AS [t0]WHERE ([t0].[WeightInKg] > @p0) AND ([t0].[ClassID] = ((    SELECT [t2].[ClassID]    FROM (        SELECT TOP (1) [t1].[ClassID]        FROM [dbo].[Class] AS [t1]        WHERE [t1].[ClassID] = @p1        ) AS [t2]    )))-- @p0: Input Float (Size = -1; Prec = 0; Scale = 0) [30]-- @p1: Input Int (Size = -1; Prec = 0; Scale = 0) [1]-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 4.0.30319.1

可以看到是兩個sql語句,第二個sql語句中AssociateWith起了作用,第一個條件是體重大於@p0,第二個條件是classID;可以看到這兒產生的sql語句很不好,ClassID是唯一主鍵,按理說DataContext已經知道這事兒,但是在產生語句時還是用了嵌套的查詢,可以說是LINQ to SQL的一個敗筆。

linq to sql相關隨筆:

1.  從CUD開始,如何使用LINQ  to SQL插入、修改、刪除資料

2.  查詢 使用LINQ to SQL做簡單查詢

3.  查詢 消極式載入與立即載入,使用LoadWith和AssociateWith

4.  查詢 inner join,left outer join

5.  Linq to SQL中的彙總grouping having

6.  LINQ to SQL查詢最佳化,需要憂慮效能嗎?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.