zoukankan      html  css  js  c++  java
  • LINQ to SQL系列三 使用DeferredLoadingEnabled,DataLoadOption指定加载选项

    本文中举例用到的数据模型如下:

    Student和Class之间是多对一关系,Student和Course之间是多对多关系。

    DataContext的DeferredLoadingEnabled属性指定是否需要延时加载,其默认值为true。以Student为例,其延时加载的对象是指Class和对应的Course。设定延时加载为true时,当访问到Student实例的Class属性或者StudentCourse属性时会自动加载Class表和StudentCourse表中的数据,如下示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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语句:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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.1
     
    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.1

    用到了两个sql语句,在我们访问到Student的Class属性时,DataContext自动去加载了Class的数据。

    在有些时候可以将DeferredLoadingEnabled属性设置为false,设置为false时再直接访问Student的Class属性时将抛出空引用的异常。

    有了延时加载,LoadWith方法是做什么用的呢?

    MSDN上对LoadWith的解释是:通过使用 lambda 表达式检索与主目标相关的指定数据。

    LoadWith不是DataContext的方法,而是DataLoadOptions的方法,可以给DataContext设定 LoadOptions属性来改变DataContext加载数据的方式;换句话说是LoadOptions设定是否在select主表数据时同时用 join加载关联表的数据。

    假定场景:我希望在select Student表的数据时同时用一个sql将其class的属性select出来,如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    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:

    1
    2
    3
    4
    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公斤的学生的信息,也就是说在取得关联表数据时附加了条件,请看下面的代码及注释:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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(" {0}",item.Name);
                }
            }
        }
        Console.ReadLine();
    }

    同样看下代码执行的真实SQL语句:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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.1
     
    SELECT [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的一个败笔。

  • 相关阅读:
    Linux运维工作总结教训
    java-GC
    java设计模式-原形模式
    java-桥接模式
    java-装饰者模式
    java-正则表达式
    java设计模式-建造者模式
    Python 条件与循环
    Python 集合、字典、运算符
    Python 字符串拼接、格式化输出、深浅复制
  • 原文地址:https://www.cnblogs.com/hbsfgl/p/4936498.html
Copyright © 2011-2022 走看看