1.  基本的数据关系图

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.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出来,如下代码:

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.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的一个败笔。

Linq中DeferredLoadingEnabled,DataLoadOption的用法的更多相关文章

  1. LINQ中的连接(join)用法示例

    Linq中连接主要有组连接.内连接.左外连接.交叉连接四种.各个用法如下. 1. 组连接 组连接是与分组查询是一样的.即根据分组得到结果. 如下例,根据publisther分组得到结果. 使用组连接的 ...

  2. linq中group by 的用法

    如下代码: var dates=(from p in points group p by p.LevelId into g select new { g.Key,g });之后 你会拿到这个数组: 之 ...

  3. Linq中关键字的作用及用法

    Linq中关键字的作用及用法 1.All:确定序列中的所有元素是否都满足条件.如果源序列中的每个元素都通过指定谓词中的测试,或者序列为空,则为 true:否则为 false. Demo: 此示例使用 ...

  4. Linq中join & group join & left join 的用法

    Linq中join & group join & left join 的用法 2013-01-30 11:12 12154人阅读 评论(0) 收藏 举报  分类: C#(14)  文章 ...

  5. 简述Linq中.ToList(), .AsEnumerable(), AsQueryable()的区别和用法

    [TOC] 这3个方法的功能完全不同, 应按照具体业务场景使用. AsQueryable() 先说说什么是 IQueryable IQueryable 是当前的 data provider 返回的类型 ...

  6. Linq中 AsQueryable(), AsEnumerable()和ToList()的区别和用法

    Linq中 AsQueryable(), AsEnumerable()和ToList()的区别和用法:在写LINQ语句的时候,往往会看到AsEnumerable() ,AsQueryable() 和T ...

  7. MVC+Spring.NET+NHibernate .NET SSH框架整合 C# 委托异步 和 async /await 两种实现的异步 如何消除点击按钮时周围出现的白线? Linq中 AsQueryable(), AsEnumerable()和ToList()的区别和用法

    MVC+Spring.NET+NHibernate .NET SSH框架整合   在JAVA中,SSH框架可谓是无人不晓,就和.NET中的MVC框架一样普及.作为一个初学者,可以感受到.NET出了MV ...

  8. Linq 中 Join 的用法

    Linq中连接主要有组连接.内连接.左外连接.交叉连接四种.各个用法如下. 注:本文内容主要来自<Linq实战>,本例中用到的对象请见文章底部. 1. 组连接 组连接是与分组查询是一样的. ...

  9. LINQ中的Aggregate用法总结

    Aggregate这个语法可以做一些复杂的聚合运算,例如累计求和,累计求乘积.它接受2个参数,一般第一个参数是称为累积数(默认情况下等于第一个值),而第二个代表了下一个值.第一次计算之后,计算的结果会 ...

随机推荐

  1. jvm调优(二)

    栈内存溢出,主要发生在大数据批量处理的情况,一般解决方案:1.加大栈内存 2.分批处理(用事物,全通过则通过,没有通过则回滚) cpu过高,死锁啊,内存过高啊,i/0问题啊 都可以看 线程栈 jsta ...

  2. DAY7-面向对象之继承与派生

    一.初识继承 什么是继承 继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类. 子类会“”遗传”父类的属性,从而解决代 ...

  3. 《Android应用性能优化》 第6章 性能评测和剖析

    1.时间测量 System.currentTimeMillis 精读和准确度可能不够:更改系统时间会影响结果:UTC时间1970/1/1 00:00:00到现在的毫秒数 System.nanoTime ...

  4. ARC100C Linear Approximation

    传送门 分析 这道题真的好水呀QwQ,想必大家都知道对于式子|x-2|+|x-3|x取什么值可以使式子结果最小,这道题也是这个原理,只需要将要额外减的1.2.3……提前减掉就行了. 代码 #inclu ...

  5. Luogu 4409 [ZJOI2006]皇帝的烦恼

    BZOJ 1863 lyd口中的夹B递推. 挺妙的解法. 第一个感觉是找到一个最大的相邻的$a_i + a_{i - 1}$就可以了,但是这个想法大概只对了一半,一半的意思是说只有在$n$为偶数的时候 ...

  6. Luogu 2737 [USACO4.1]麦香牛块Beef McNuggets

    NOIP2017 D1T1 的结论,两个数$a, b$所不能表示出的最大的数为$a * b - a - b$. 听了好几遍证明我还是不会 注意到本题中给出的数都非常小,所以最大不能表示出的数$\leq ...

  7. discuz_ucenter_api_for_java的中文问题

    我踩过的坑,希望你别掉进来. 云服务需要和UCENTER做对接,一个php,一个Java,幸好有了discuz_ucenter_api_for_java,帮我解决了大部分问题,为什么是大部分问题,因为 ...

  8. android listview addHeaderView和addFooterView的注意事项

    1. item内如果有button等控件时,在监听listview的onitemclick事件时,焦点会被item内的button. imagebutton等控件抢走,从而导致在listview设置了 ...

  9. TinkerPop中的遍历:图的遍历步骤(3/3)

    48 Project Step project() 步骤(map)将当前对象投射到由提供的标签键入的Map<String,Object>中. gremlin> g.V().out(' ...

  10. [译]Javascript中的本地以及全局变量

    本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...