`

《深入了解 Linq to SQL》之对象的标识 —— 麦叔叔呕心呖血之作

阅读更多
原帖地址:http://www.cnblogs.com/ansiboy/archive/2013/06/13/3130240.html

序言


很多朋友都向我提过,希望我写一下关于Linq to SQL 或者 VS 插件方面的文章。尽管市面上有很多 Linq to SQL 的书籍,但是都是介绍怎么用,缺乏深度。关于 VS 插件方面的书籍也是很显浅,按书籍做出来的东西,只能是学生级别的东西,根本拿不出手。他们觉得我有这个能力写好。


从技术能力的角度来说,的确是不存在什么问题,但是,要把一门技术讲精讲透,是花很时间的事情。自己付出了很多,如果不能得到读者的认同,那这个专题写下去也没什么意义了。这个专题不是教你怎么使用Linq to SQL,而是让你明白Linq to SQL的原理,对于想写ORM的朋友,绝对不可错过。写完《深入了解 Linq to SQL》这个系列后,下一个系列就是《VS 插件开发了》,所以,大家如果希望我继续写下去,请记得点推荐。你们的推荐,就是我写下去的动力。


概述


关于对象的标识,简单点说,就是主键相同的对象,在数据上下文的缓存中,只有一个。数据上下文,在加载数据,创建对象之后,接着对所创建的每个实体类的对象,都会克隆一份对象副本(浅复制)记住这点,我们在后面要用到,用来保存对象的初始值,当对象的属性值修改后,副本的属性值是不改的。注意,只有实体类对象才会创建对象副本,而匿名类对象是不会生成副本,也只实体。我们看下面一段代码:


例一



var c1 = db.Categories.Single(o => o.CategoryId == 1);
var c2 = db.Categories.Single(o => o.CategoryId == 1);


在例一这个例子中,c1、c2 是相等的,我们再来看下面一个例子:


例二



var c1 = db.Categories.Select(o => new { o.CategoryId, o.CategoryName }).Single(o => o.CategoryId == 1);
var c2 = db.Categories.Select(o => new { o.CategoryId, o.CategoryName }).Single(o => o.CategoryId == 1);


这个例二这个例子中,c1、c2 是不相等的。


为什么匿名对象不支持对象标识呢?因为匿名对象,不一定有主键。而 Linq to SQL ,是通过实体的主键来标识一个实体对象的,当从数据库加载完数据,会先根据主键检索缓存中是否有已经存在的对象,没有才会创建对象。这样会引起一个什么样的问题呢?执行下面的代码。



var c1 = db.Categories.Single(o => o.CategoryId == 1);


假设 CategoryId 为 1 的 CategoryName 为 “Beverages”,打开数据库,把该值改为“New Name”后,如下图:


图一



然后再执行下面的代码:



var c2 = db.Categories.Single(o => o.CategoryId == 1);


这时候 c2 修改后的 c2.CategoryName 的值是什么呢?仍然为“Beverages”!因为第二次加载完数据的时候,由于已经存在了主键(CategoryID)为“1”的Category,所以在第二次的加载中,不再创建新的对象,以是使用之前所创建的Category对象。那怎么样才能使用 c2 的 CategoryName 的值为最新值“New Name”呢?调用数据上下文的 Refresh 方法即可。



 db.Refresh(RefreshMode.OverwriteCurrentValues, c2);


跟踪属性的更改


我们先来看一个更新的例子:



var c1 = db.Categories.Single(o => o.CategoryId == 1);
c1.CategoryName
= "xxx";
db.SubmitChanges();

c1.CategoryName
= "xxx";
db.SubmitChanges();


通过查看生成的SQL,我们可以发现,尽管 SubmitChagens 方法执行了两次,但是实际上SQL只执行了一次,因为第二次的 CategoryName 并没有修改,那么Linq to SQL如何得知某一个属性是修改了或者没有呢?我们看Category实体类的定义,为了节省篇幅,只选取一部份。



[Table(Name="Categories")]
public partial class Category : INotifyPropertyChanging, INotifyPropertyChanged
{
[Column(Storage
="_CategoryName", DbType="VarChar(15)", CanBeNull=false, UpdateCheck=UpdateCheck.Never)]
public string CategoryName
{
get
{
return this._CategoryName;
}
set
{
if ((this._CategoryName != value))
{
this.OnCategoryNameChanging(value);
this.SendPropertyChanging();
this._CategoryName = value;
this.SendPropertyChanged("CategoryName");
this.OnCategoryNameChanged();
}
}
}


protected virtual void SendPropertyChanged(String propertyName)
{
if ((this.PropertyChanged != null))
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}


我们可以看得到,实体类Category实现了 INotifyPropertyChanged 的接口,通过这个接口,就可以得知某个属性是否已经更改了,但是,事实上Category实体类不实现上面的接口,也是没有问题的,如下所示:



[Table(Name = "Categories")]
public partial class Category
{
[Column(Storage
= "_CategoryName", DbType = "VarChar(15)", CanBeNull = false, UpdateCheck = UpdateCheck.Never)]
public string CategoryName
{
get { return this._CategoryName; }
set { this._CategoryName = value; }
}
}


 为什么这样也可以呢?记得我们刚才说到对象副本吗?当 Category 没有实现 INotifyPropertyChanged 这个接口时,Linq to SQL会将Category实体对象和原始的对象副本作比较来得知Category的属性值是否更改了。


但是下面的定义,会导致 CategoryName 的值即使用修改了,也不会更新到数据库。因为,当 CategoryName 的值发生变化的,并没有通知到接口 INotifyPropertyChanged,而当实体类继承于INotifyPropertyChanged时,Linq to SQL是依赖INotifyPropertyChanged来获取值被更改的属性。



[Table(Name = "Categories")]
public partial class Category: INotifyPropertyChanged
{
[Column(Storage
= "_CategoryName", DbType = "VarChar(15)", CanBeNull = false, UpdateCheck = UpdateCheck.Never)]
public string CategoryName
{
get { return this._CategoryName; }
set { this._CategoryName = value; }
}
}


由上面我们可以知道,通过对象标识,可以使得Model的定义最为简洁,在Linq to SQL的设计里,你会常常可以看到,很多地方都遵循简洁模型这个原则,这个原则,在后面的内容里会给大家介绍。同时你会发现,如果对于没有定义好主键的实体,是不能进行添加、更新、删除的操作,因为这些操作都依赖于对象标识,而对象标识又需要实体的主键。又因为主键是用来标识对象的,所以主键是不能何改的。


备注


ALinq 提供了 Insert、Update、Delete 三个方法,这三个方法,只是简单地将 Linq 的 Lamdba 表达式转成 SQL 语句然后再执行。因此,它不依赖于对象标识。所以它可以:


1、没有主键也能更新


2、可以更新主键的值


总之,SQL 能操作的,它都可以。关于这几个方法的使用,ALinq 的文档中都有介绍,看文档即可。


 


 


 


 

本文链接

分享到:
评论

相关推荐

    一步步学LINQ to SQL(一)——LINQ to SQL入门.pdf

    一步步学LINQ to SQL(一)——LINQ to SQL入门.pdf

    一步步学LINQ to SQL(二)——LINQ to SQL对数据库增、删、改及查询.pdf

    一步步学LINQ to SQL(二)——LINQ to SQL对数据库增、删、改及查询.pdf

    一个简单的linq to sql例子

    虽然LINQ to SQL在.NET框架的最新版本中已被Entity Framework所取代,但了解它的基本工作原理对于理解ORM(对象关系映射)的概念仍然很有帮助。 在压缩包`linqDemo`中,可能包含了实现上述操作的完整C#项目文件,你...

    linq基础 linq to sql

    本教程主要关注LINQ的基础以及其在SQL数据库操作中的应用——LINQ to SQL。 一、LINQ的基本概念 1. 查询表达式:LINQ引入了一种新的查询语法,类似于SQL,但它是合法的C#或VB代码。这种语法使查询直观且易于理解。 ...

    LINQ to SQL.rar

    **LINQ to SQL** 是微软.NET Framework中的一种技术,它允许开发者使用C#或VB.NET语言的查询表达式(Language Integrated Query,简称LINQ)直接对SQL数据库进行操作。这项技术将关系数据库的数据操作与对象模型无缝...

    LINQ To SQL实现分页效果源码

    LINQ (Language Integrated Query) 是.NET框架中的一种技术,它允许开发者使用类似SQL的查询语法在C#或VB.NET等编程语言中操作对象。在本例中,我们关注的是LINQ to SQL,这是一种特定的LINQ实现,它用于与关系...

    Linq To Sql进阶系列

    - **映射概念**:Linq To Sql的核心之一在于它能够实现数据库表与.NET类之间的自动映射。这种映射方式极大地简化了开发过程中的数据访问层编写工作。 - **解决的问题**:传统.NET应用中,通常需要手动编写SQL语句来...

    Linq to sql 教程

    1. **Linq简介**:首先了解Linq的基本概念和它在.NET框架中的地位,以及Linq to sql与其他Linq技术(如Linq to Objects、Linq to XML等)的区别。 2. **安装与配置**:介绍如何在Visual Studio中设置Linq to sql...

    LINQ TO SQL DEMO

    综上所述,"LINQ TO SQL DEMO"项目是一个全面了解和掌握LINQ to SQL技术的好资源。通过分析和运行这个DEMO,开发者可以深入理解如何使用LINQ查询语言进行数据库操作,以及如何通过DataContext管理数据库事务。

    LINQ to SQL可视化调试工具

    **LINQ to SQL 可视化调试工具** LINQ (Language Integrated Query) 是.NET Framework中的一项强大技术,它允许开发者使用自然的编程语言语法来查询数据。LINQ to SQL是.NET Framework下的一个ORM(Object-...

    Linq to sql 和 Linq to Entity 高级查询

    实现linq多个查询条件连接功能(支持linq to sql 和linq to entity)。 按多个指定属性排序功能。 不同参数的lamdba表达式条件间的转换功能。

    LINQ To Sql学习文档

    ### LINQ To Sql 学习文档关键知识点解析 #### 一、LINQ To Sql 概览 **LINQ (Language Integrated Query)** ...随着对 LINQ To SQL 的深入了解和实践,开发者将能够更好地利用这一强大工具,为项目带来更大的价值。

    linq to sql 学习笔记

    在深入学习LINQ to SQL之前,我们需要了解一些基础概念: - **什么是LINQ to SQL**:它是.NET Framework 3.5引入的一个ORM(对象关系映射)工具,使开发者能够使用C#或VB.NET的查询表达式来操作数据库,将SQL查询...

    c#linq to sql

    C# LINQ to SQL 是微软.NET Framework中的一种数据查询技术,它允许开发人员使用C#语言直接对SQL数据库进行操作,极大地简化了数据库交互的工作。LINQ(Language Integrated Query,语言集成查询)是.NET Framework ...

    LINQ to SQL手册

    **LINQ to SQL** 是 .NET Framework 中的一个技术,它允许开发者使用 C# 或 VB.NET 语言的查询表达式语法来操作数据库。本手册详细介绍了使用 LINQ to SQL 进行数据查询、操作和更新的各种方法,涵盖了从基础到高级...

    Linq To SQL

    **LINQ to SQL** 是.NET Framework 3.5中引入的一种对象关系映射(ORM)技术,它允许开发者使用C#或VB.NET等.NET语言直接对数据库进行操作,而无需编写大量的SQL语句。通过LINQ(Language Integrated Query),...

    ASP.NET MVC+LINQ TO SQL登陆

    在这个场景中,我们将讨论如何在ASP.NET MVC项目中实现一个使用LINQ to SQL的登录功能。 LINQ(Language Integrated Query,语言集成查询)是.NET Framework的一部分,它允许开发者使用C#或VB.NET等语言的语法来...

    Linq to Sql 教程大全

    ### Linq to Sql 教程大全 #### 一、LINQ to SQL 概述 **LINQ to SQL** 是一种使开发人员能够使用面向对象的方法访问数据库的技术。它提供了将数据库表映射到.NET Framework中类的能力,允许开发人员通过编写LINQ...

    一步一步学 Linq to sql

    Linq to Sql 是 LINQ (Language Integrated Query) 的一个组成部分,通过它可以将数据库对象映射为 .NET 对象,从而简化数据操作。 1. **隐含类型局部变量**: 使用 `var` 关键字可以避免在声明变量时明确指定类型...

    浅谈Linq to sql 的多表关联与动态条件查询

    在 Linq to sql 中,我们可以使用 Expression<T> 对象来实现动态条件查询。例如: ``` Expression, bool>> lambda = ar => (1 == 1); if (id != null) lambda = (ar => ar.Id == id); var article = db.Articles....

Global site tag (gtag.js) - Google Analytics