首页 > 数据库 >LINQ to SQL语句之对象标识和对象加载

LINQ to SQL语句之对象标识和对象加载

时间:2023-05-21 16:32:58浏览次数:31  
标签:检索 对象 LINQ 查询 SQL var ds 加载


[list]
[*]对象标识
[/list]
运行库中的对象具有唯一标识。引用同一对象的两个变量实际上是引用此对象的同一实例。你更改一个变量后,可以通过另一个变量看到这些更改。
关系数据库表中的行不具有唯一标识。由于每一行都具有唯一的主键,因此任何两行都不会共用同一键值。
实际上,通常我们是将数据从数据库中提取出来放入另一层中,应用程序在该层对数据进行处理。这就是 LINQ to SQL 支持的模型。将数据作为行从数据库中提取出来时,你不期望表示相同数据的两行实际上对应于相同的行实例。如果您查询特定客户两次,您将获得两行数据。每一行包含相同的信息。

对于对象。你期望在你反复向 DataContext 索取相同的信息时,它实际上会为你提供同一对象实例。你将它们设计为层次结构或关系图。你希望像检索实物一样检索它们,而不希望仅仅因为你多次索要同一内容而收到大量的复制实例。

在 LINQ to SQL 中,DataContext 管理对象标识。只要你从数据库中检索新行,该行就会由其主键记录到标识表中,并且会创建一个新的对象。只要您检索该行,就会将原始对象实例传递回应用程序。通过这种方式,DataContext 将数据库看到的标识(即主键)的概念转换成相应语言看到的标识(即实例)的概念。应用程序只看到处于第一次检索时的状态的对象。新数据如果不同,则会被丢弃。

LINQ to SQL 使用此方法来管理本地对象的完整性,以支持开放式更新。由于在最初创建对象后唯一发生的更改是由应用程序做出的,因此应用程序的意向是很明确的。如果在中间阶段外部某一方做了更改,则在调用 SubmitChanges() 时会识别出这些更改。

以上来自MSDN,的确,看了有点“正规”,下面我用两个例子说明一下。
[list]
[*]对象缓存
[/list]

在第一个示例中,如果我们执行同一查询两次,则每次都会收到对内存中同一对象的引用。很明显,cust1和cust2是同一个对象引用。

Customer cust1 = db.Customers.First(c => c.CustomerID == "BONAP");Customer cust2 = db.Customers.First(c => c.CustomerID == "BONAP");下面的示例中,如果您执行返回数据库中同一行的不同查询,则您每次都会收到对内存中同一对象的引用。cust1和cust2是同一个对象引用,但是数据库查询了两次。

Customer cust1 = db.Customers.First(c => c.CustomerID == "BONAP");Customer cust2 = ( from o in db.Orders where o.Customer.CustomerID == "BONAP" select o ) .First() .Customer;

[list]
[*]对象加载
[/list]

延迟加载
在查询某对象时,实际上你只查询该对象。不会同时自动获取这个对象。这就是延迟加载。

例如,您可能需要查看客户数据和订单数据。你最初不一定需要检索与每个客户有关的所有订单数据。其优点是你可以使用延迟加载将额外信息的检索操作延迟到你确实需要检索它们时再进行。请看下面的示例:检索出来CustomerID,就根据这个ID查询出OrderID。

var custs = from c in db.Customers where c.City == "Sao Paulo" select c;//上面的查询句法不会导致语句立即执行,仅仅是一个描述性的语句,只有需要的时候才会执行它foreach (var cust in custs){ foreach (var ord in cust.Orders) { //同时查看客户数据和订单数据 }}语句描述:原始查询未请求数据,在所检索到各个对象的链接中导航如何能导致触发对数据库的新查询。
[list]
[*]预先加载:LoadWith 方法
[/list]

你如果想要同时查询出一些对象的集合的方法。LINQ to SQL 提供了 DataLoadOptions用于立即加载对象。方法包括:
LoadWith 方法,用于立即加载与主目标相关的数据。
AssociateWith 方法,用于筛选为特定关系检索到的对象。

使用 LoadWith方法指定应同时检索与主目标相关的哪些数据。例如,如果你知道你需要有关客户的订单的信息,则可以使用 LoadWith 来确保在检索客户信息的同时检索订单信息。使用此方法可仅访问一次数据库,但同时获取两组信息。
在下面的示例中,我们通过设置DataLoadOptions,来指示DataContext在加载Customers的同时把对应的Orders一起加 载,在执行查询时会检索位于Sao Paulo的所有 Customers 的所有 Orders。这样一来,连续访问 Customer 对象的 Orders 属性不会触发新的数据库查询。在执行时生成的SQL语句使用了左连接。

NorthwindDataContext db = new NorthwindDataContext();DataLoadOptions ds = new DataLoadOptions();ds.LoadWith<Customer>(p => p.Orders);db.LoadOptions = ds;var custs = ( from c in db2.Customers where c.City == "Sao Paulo" select c);foreach (var cust in custs){ foreach (var ord in cust.Orders) { Console.WriteLine("CustomerID {0} has an OrderID {1}.", cust.CustomerID, ord.OrderID); }}语句描述:在原始查询过程中使用 LoadWith 请求相关数据,以便稍后在检索到的各个对象中导航时不需要对数据库进行额外的往返。
[list]
[*]延迟加载:AssociateWith方法
[/list]

使用 AssociateWith 方法指定子查询以限制检索的数据量。
在下面的示例中,AssociateWith 方法将检索的 Orders 限制为当天尚未装运的那些 Orders。如果没有此方法,则会检索所有 Orders,即使只需要一个子集。但是生成SQL语句会发现生成了很多SQL语句。

NorthwindDataContext db2 = new NorthwindDataContext();DataLoadOptions ds = new DataLoadOptions();ds.AssociateWith<Customer>( p => p.Orders.Where(o => o.ShipVia > 1));db2.LoadOptions = ds;var custs = from c in db2.Customers where c.City == "London" select c;foreach (var cust in custs){ foreach (var ord in cust.Orders) { foreach (var orderDetail in ord.OrderDetails) { //可以查询出cust.CustomerID, ord.OrderID, ord.ShipVia, //orderDetail.ProductID, orderDetail.Product.ProductName } }}语句描述:原始查询未请求数据,在所检索到各个对象的链接中导航如何以触发对数据库的新查询而告终。此示例还说明在延迟加载关系对象时可以使用 Assoicate With 筛选它们。
[list]
[*]预先加载:LoadWith方法和Associate With方法
[/list]
这个例子说明:使用LoadWith方法来确保在检索客户信息的同时检索订单信息,在检索订单信息的同时检索订单详细信息, 仅仅访问一次数据库。即可以在一个查询中检索许多对象。使用Associate With方法来限制订单详细信息的排序规则。

NorthwindDataContext db2 = new NorthwindDataContext();DataLoadOptions ds = new DataLoadOptions();ds.LoadWith<Customer>(p => p.Orders);ds.LoadWith<Order>(p => p.OrderDetails);ds.AssociateWith<Order>( p => p.OrderDetails.OrderBy(o => o.Quantity));db2.LoadOptions = ds;var custs = ( from c in db2.Customers where c.City == "London" select c);foreach (var cust in custs){ foreach (var ord in cust.Orders) { foreach (var orderDetail in ord.OrderDetails) { //查询cust.CustomerID, ord.OrderID //orderDetail.ProductID, orderDetail.Quantity } }}语句描述:在原始查询过程中使用 LoadWith 请求相关数据,以便稍后在检索到的各个对象中导航时此示例还说明在急切加载关系对象时可以使用 Assoicate With 对它们进行排序。

[list]
[*]加载重写
[/list]

这个例子在Category类里提供了一个LoadProducts分部方法。当产品的类别被加载的时候,就直接优先调用了LoadProducts方法来查询没有货源的产品。

private IEnumerable<Product> LoadProducts(Category category){ //在执行LINQ to SQL的时候,这个LoadProducts分部方法 //优先加载执行,这里用存储过程也可以. return this.Products .Where(p => p.CategoryID == category.CategoryID) .Where(p => !p.Discontinued);}执行下面的查询时,利用上面方法返回的数据进行下面的操作:

NorthwindDataContext db2 = new NorthwindDataContext();DataLoadOptions ds = new DataLoadOptions();ds.LoadWith<Category>(p => p.Products);db2.LoadOptions = ds;var q = ( from c in db2.Categories where c.CategoryID < 3 select c);foreach (var cat in q){ foreach (var prod in cat.Products) { //查询cat.CategoryID, prod.ProductID }}语句描述:重写 Category 类中的分部方法 LoadProducts。加载某种类别的产品时,调用 LoadProducts 以加载此类别中未停产的产品。

标签:检索,对象,LINQ,查询,SQL,var,ds,加载
From: https://blog.51cto.com/u_4387387/6319683

相关文章

  • Docker 启动 [email protected] 并使用 Navicat 客户端连接
    docker运行mysql镜像dockerrun--namesome-mysql-p3306:3306-eMYSQL_ROOT_PASSWORD=my-secret-pw-dmysql:5.7其中some-mysql是您要分配给容器的名称my-secret-pw是要为MySQLroot用户设置的密码-p将容器的3306端口发布到主机的端口3306-e设置容器的环境......
  • Java面向对象中“匿名对象”的使用
    1.0匿名对象的基本知识匿名对象顾名思义,匿名对象指的就是没有名字的对象,在使用中理解为实例化一个类对象,但是并不把它赋给一个对应的类变量,而是直接使用。在理解匿名对象前,我们先创建一个类便于后面的使用。匿名对象具有以下特征:语法上:只创建对象,但不用变量来接收,例如:假设现......
  • 【转发】C#连接sql server数据库的方法
    1、连接SQLEXPRESSA)、连接到SQLServerExpressEdition数据库,下面的连接字符串连接到一个名为Database1的数据库:DataSource=.\SQLEXPRESS;InitialCatalog=Database1;IntegratedSecurity=True;B)、连接数据库文件Database1(VS自带SQLEXPRESS)DataSource=.\SQLEXPRESS;Att......
  • Windows 2012安装mysql 5.7.21
    文档课题:Windows2012安装mysql5.7.21系统:MicrosoftWindowsServer2012Standard64位数据库:mysql5.7.21安装包:mysql-installer-community-5.7.21.0.msi1、下载自MySQL版本升级到5.7后,安装和配置过程发生很大变化,以下介绍5.7版本MySQL的下载、安装及配置过程.针对不同......
  • C#学习笔记 -- 对象初始化语句、索引器、访问器的修饰符
    1、对象初始化语句扩展语法有如下两种扩展语法,第一种当类中没有声明构造器或者声明了无参构造器才能用第二种当类中声明了有参构造器才能用newExampleClass{FieldOrProp=InitProp,FieldOrProp=InitProp,...};newExampleClass(ArgList){FieldOrProp=I......
  • 彻底掌握 MySQL InnoDB 的锁机制
    本文是对沈剑大佬锁机制十多篇文章的概括总结,文末有全部链接,还参考了10多位其他网友的优秀分享。1、概要MySQL中的锁可以按照粒度分为锁定整个表的表级锁(table-levellocking)和锁定数据行的行级锁(row-levellocking):表级锁具有开销小、加锁快的特性;但是表级锁的锁定粒度较大,发生......
  • 详解C++STL—函数对象
    1、函数对象1.1、函数对象概念概念:重载函数调用()操作符的类,其对象常称为函数对象函数对象使用重载的()时,行为类似函数调用,也叫仿函数本质:函数对象(仿函数)是一个类,不是一个函数1.2、函数对象的使用特点:函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值函数对象超......
  • MSSQLServer和SQL Server Express、LocalDB的区别
    转载:https://www.cnblogs.com/lucky-donkey/p/13544916.html MSSQLServer:全称MicrosoftSQL Server,微软的数据库服务。SQLServerExpress:MicrosoftSQL Server的一个免费版,功能上有一些限制。                  1.数据库的大小限制:SQ......
  • SQL ERVER 表转化为C#实体(SQL 代码)
    本文推出SqlServer表转化为实体的sql代码在VS中有可以自带生成实体类的快捷操作,但是生成的代码比较杂乱,很多东西都是不需要的,一个一个去敲又很浪费时间,关键太无聊了在闲暇之余写一份代码供大家学习,废话不多说,直接整干货:DECLARE@TableNamesysname='[dbo].[Orders]';--要生......
  • MySQL索引优化
    1.索引是啥?简单来说是可以快速查找数据的数据结构。数据结构就是存储数据的结构,例如数组,链表...在数据库系统中还维护着满足特定查找算法的数据结构,这些数据结构以某种引用指向表中是数据,这些数据结构就是索引,它让我们可以用算法来查找数据。假设有个user表,通过name字段找李白,没有......