Linq中DeferredLoadingEnabled,DataLoadOption的用法
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的用法的更多相关文章
- LINQ中的连接(join)用法示例
Linq中连接主要有组连接.内连接.左外连接.交叉连接四种.各个用法如下. 1. 组连接 组连接是与分组查询是一样的.即根据分组得到结果. 如下例,根据publisther分组得到结果. 使用组连接的 ...
- linq中group by 的用法
如下代码: var dates=(from p in points group p by p.LevelId into g select new { g.Key,g });之后 你会拿到这个数组: 之 ...
- Linq中关键字的作用及用法
Linq中关键字的作用及用法 1.All:确定序列中的所有元素是否都满足条件.如果源序列中的每个元素都通过指定谓词中的测试,或者序列为空,则为 true:否则为 false. Demo: 此示例使用 ...
- Linq中join & group join & left join 的用法
Linq中join & group join & left join 的用法 2013-01-30 11:12 12154人阅读 评论(0) 收藏 举报 分类: C#(14) 文章 ...
- 简述Linq中.ToList(), .AsEnumerable(), AsQueryable()的区别和用法
[TOC] 这3个方法的功能完全不同, 应按照具体业务场景使用. AsQueryable() 先说说什么是 IQueryable IQueryable 是当前的 data provider 返回的类型 ...
- Linq中 AsQueryable(), AsEnumerable()和ToList()的区别和用法
Linq中 AsQueryable(), AsEnumerable()和ToList()的区别和用法:在写LINQ语句的时候,往往会看到AsEnumerable() ,AsQueryable() 和T ...
- 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 ...
- Linq 中 Join 的用法
Linq中连接主要有组连接.内连接.左外连接.交叉连接四种.各个用法如下. 注:本文内容主要来自<Linq实战>,本例中用到的对象请见文章底部. 1. 组连接 组连接是与分组查询是一样的. ...
- LINQ中的Aggregate用法总结
Aggregate这个语法可以做一些复杂的聚合运算,例如累计求和,累计求乘积.它接受2个参数,一般第一个参数是称为累积数(默认情况下等于第一个值),而第二个代表了下一个值.第一次计算之后,计算的结果会 ...
随机推荐
- [Chapter 3 Process]Practice 3.2 Including the initial parent process, how many processes are created by the program shown in Figure?
3.2 Including the initial parent process, how many processes are created by the program shown in Fig ...
- 第二章 深入分析Java I/O的工作机制(待续)
Java的I/O类库的基本架构 磁盘I/O工作机制 网络I/O工作机制 NIO的工作方式 I/O调优 设计模式解析之适配器模式 设计模式解析之装饰器模式 适配器模式与装饰器模式的区别
- eclipse安卓模拟器Failed to install on device 'emulator-5554': timeout处理方案
我们在用模拟器调试的时候,经常会出现Failed to install on device 'emulator-5554': timeout这个错误.其实就是有些虚拟器在部署的时候时间过于长.系统就认 ...
- Android studio导入svn工程
Quick Start——> Check outproject from Version——> Subversion——> ‘+’加号 ——> 输入网址 ——> 注意选择 ...
- sql基本查询语句练习
student(S#,Sname,Sage,Ssex) 学生表 S#:学号: Sname:学生姓名:Sage:学生年龄:Ssex:学生性别 Course(C#,Cname,T#) 课程表 ...
- [poj2976]Dropping tests(01分数规划,转化为二分解决或Dinkelbach算法)
题意:有n场考试,给出每场答对的题数a和这场一共有几道题b,求去掉k场考试后,公式.的最大值 解题关键:01分数规划,double类型二分的写法(poj崩溃,未提交) 或者r-l<=1e-3(右 ...
- 使用Java读取JSON数据
----------------siwuxie095 JSON 官网:http://www.json.org/ 在官网页面的下方,是 JSON ...
- Entity Framework Tutorial Basics(19):Change Tracking
Change Tracking in Entity Framework: Here, you will learn how entity framework tracks changes on ent ...
- 数据结构与算法(Java版)_堆
完全二叉树叫做堆. 完全二叉树就是最后一个节点之前不允许有不满的节点,就是不允许有空洞. 可以使用数组来做完全二叉树(堆). 堆分为大顶堆和小顶堆.大顶堆就是根节点上的数字是最大的,小顶堆就是根节点上 ...
- centos中JDK版本冲突的问题
在centos环境下,我JDK版本安装了jdk6,jdk7.系统还自带了一个JDK7. 我在查看JDK版本是,发现不是我在/etc/profile中配置的. 1:which java 查看Java的命 ...