运行时中的对象具有唯一标识。 引用同一对象的两个变量实际上引用了该对象的同一实例。 因此,通过一个变量的路径进行的更改会立即通过另一个变量可见。
关系数据库表中的行没有唯一标识。 由于每行都有唯一的主键,因此没有两行共享相同的键值。 但是,此事实仅限制数据库表的内容。
实际上,数据最常被带出数据库并进入另一层,其中应用程序使用它。 这是 LINQ to SQL 支持的模型。 当数据作为行从数据库中取出时,你并不期望表示相同数据的两行实际上对应于同一行实例。 如果查询特定客户两次,则会收到两行数据。 每行都包含相同的信息。
对于对象,您的期望则大不一样。 你预计,如果重复请求 DataContext 相同的信息,它实际上会提供相同的对象实例。 你期望此行为,因为对象对应用程序具有特殊意义,并且你期望它们的行为与对象类似。 你将其设计为层次结构或图形。 您希望像检索实物一样检索它们,而不希望仅仅因为您多次索要同一内容而收到大量的复制实例。
在 LINQ to SQL 中 DataContext ,管理对象标识。 每当从数据库中检索新行时,该行将按其主键记录在标识表中,并创建新对象。 每当检索同一行时,原始对象实例将移交给应用程序。 通过这种方式,将 DataContext 数据库(即主键)看到的标识概念转换为语言(即实例)看到的标识概念。 应用程序仅看到其首次检索到的状态中的对象。 如果新数据不同,将被丢弃。 有关详细信息,请参阅 从标识缓存检索对象。
LINQ to SQL 使用此方法管理本地对象的完整性,以支持乐观更新。 由于首次创建对象后发生的唯一更改是应用程序所做的更改,因此应用程序的意图是明确的。 如果在此期间有外部方的变化发生,则会在调用 SubmitChanges()
时识别这些更改。
注释
如果查询请求的对象很容易识别为已检索的对象,则不会执行任何查询。 标识表充当以前检索的所有对象的缓存。
例子
对象缓存示例 1
在此示例中,如果执行同一查询两次,则每次都会在内存中收到对同一对象的引用。
Customer cust1 =
(from cust in db.Customers
where cust.CustomerID == "BONAP"
select cust).First();
Customer cust2 =
(from cust in db.Customers
where cust.CustomerID == "BONAP"
select cust).First();
Dim cust1 As Customer = _
(From cust In db.Customers _
Where cust.CustomerID = "BONAP" _
Select cust).First()
Dim cust2 As Customer = _
(From cust In db.Customers _
Where cust.CustomerID = "BONAP" _
Select cust).First()
对象缓存示例 2
在此示例中,如果执行从数据库返回同一行的不同查询,则每次都会在内存中收到对同一对象的引用。
Customer cust1 =
(from cust in db.Customers
where cust.CustomerID == "BONAP"
select cust).First();
Customer cust2 =
(from ord in db.Orders
where ord.Customer.CustomerID == "BONAP"
select ord).First().Customer;
Dim cust1 As Customer = _
(From cust In db.Customers _
Where cust.CustomerID = "BONAP" _
Select cust).First()
Dim cust2 As Customer = _
(From ord In db.Orders _
Where ord.Customer.CustomerID = "BONAP" _
Select ord).First().Customer