从(1)我们看到,当生成entity class定义时,entity class或xml mapping文件中都已经完整的包含了entity和关系数据库的映射信息了,LINQ2SQL会根据这些信息来把CRUD操作转化为SQL提交给数据库,并且把数据库的返回DataTable封装成我们想要的对象。

所谓简单对象,就是数据表定义中没有Foreign-key的entity class,在操作这类对象时不会涉及级联的操作。

简单对象的CRUD操作,可参考MSDN:http://msdn.microsoft.com/zh-cn/library/bb399349.aspx

有一点很方便,在插入数据时,LINQ2SQL不但生成了Insert的SQL语句,而且还生成语句把ColumnAttribute标记IsDbGenerated=true的数据列取回。这点当我们用数据库生成的uniqueidentifier列或自增id做主键时尤其方便。

下面让我们来一起讨论级联操作以及相关问题,为了方便示例我定义了两张数据表Publishers和Books:

其中PublisherID和BookID都是RowGuid,而且默认值为newid(),以下代码都是基于SqlMetal生成的xml mapping和entity class。

添加

下面代码示例了在添加Publisher记录时,同时添加两个关联Book记录

var context = GenerateContext();
Publisher publisher = new Publisher { Name = "Microsoft" };
publisher.Books.Add(new Book { Title = "Expert F#" });
publisher.Books.Add(new Book { Title = "Beautiful code" });context.Publishers.InsertOnSubmit(publisher);
context.SubmitChanges();

提交成功,关联对象的添加就好像是集合操作。但是,好像缺了点什么?我们好像没有给Book.PublisherID赋值,作为外键没有赋值为什么会没抛出异常呢?这都是生成代码的功劳,我们看看Publisher.Books属性的定义

private EntitySet<Book> _Books;public Publisher()
{this._Books = new EntitySet<Book>(new Action<Book>(this.attach_Books), new Action<Book>(this.detach_Books));OnCreated();
}

当向Books集合中添加元素时,会调用attach_Books让Book.Publisher指向Publisher对象

private void attach_Books(Book entity)
{this.SendPropertyChanging();entity.Publisher = this;
}

而Book.Publisher的赋值又触发事件使Book.PublisherId=Book.Publisher.PublisherID

public Publisher Publisher{get { … }set{Publisher previousValue = this._Publisher.Entity;if (((previousValue != value) || (this._Publisher.HasLoadedOrAssignedValue == false))){this.SendPropertyChanging();if ((previousValue != null)){this._Publisher.Entity = null;previousValue.Books.Remove(this);}this._Publisher.Entity = value;if ((value != null)){value.Books.Add(this);this._PublisherID = value.PublisherID;}else{this._PublisherID = default(System.Guid);}this.SendPropertyChanged("Publisher");}}}

更新

下面代码示例了在更新Publisher记录时,同时更新相关的Book记录

Publisher publisher = context.Publishers.Where(
p => p.PublisherID == new Guid("ae825c5f-465d-4eb5-a2bb-cc1aeb5edb7d")).Single();
publisher.Name = "Updated Publisher";
var book = publisher.Books.First();
book.Title = "Updated book";context.SubmitChanges();

这样的操作我们称之为什么?级联更新?事实上LINQ2SQL的实现里不存在所谓的“级联更新“。在生命周期内,每一个DataContext对象都维护着每一个查询获得的对象的引用,并且跟踪对象的修改,所有发生了修改的对象,在调用DataContext.SubmitChanges的时候,都会被保存到数据库,这方面的内容在”LINQ那些事(6)“里会详细讨论。所以,在这里不是级联更新,而是Publisher和Book对象都发生了更改,所以在调用SubmitChanges都被保存了。

涉及Association的更新,有时还会引发异常,我们来看下面这段代码:

var context = GenerateContext();
Publisher publisher = context.Publishers.Where(
p => p.PublisherID == new Guid("ae825c5f-465d-4eb5-a2bb-cc1aeb5edb7d")).Single();
var book = publisher.Books.First();
publisher.Books.Remove(book);context.SubmitChanges();

这段代码的意图是删除Publisher对象相关的某Book对象,看起来是很漂亮的集合操作,但是运行时抛出异常:

“An attempt was made to remove a relationship between a Publisher and a Book. However, one of the relationship's foreign keys (Book.PublisherID) cannot be set to null.

还记得我们在调用Publisher.Books.Add时候,EntitySet的会调用attach_Books来修改Book.PublisherID吗?在调用Publisher.Books.Remove的时候,EntitySet会调用detach_Books来让Book.PublisherID = default(Guid)

而对于LINQ2SQL,只跟踪到了Book.PublisherID属性发生了更改,所以在调用SubmitChanges会尝试更新Book记录而产生上述外键异常。解决这个问题的方法是:在Book.PublisherID的ColumnAttribute定义中,把DeleteOnNull设为true。这样当Context发现Book.PublisherID为空(default(Guid)相当于Guid.Empty)时,不是执行Update而是Delete操作。

删除

根据msdn,目前版本的LINQ是不支持级联删除的,需要级联删除只能依赖数据库的级联删除,否则也可以考虑下面的方式:

context.Books.DeleteAllOnSubmit(publisher.Books.AsEnumerable());
context.Publishers.DeleteOnSubmit(publisher);
context.SubmitChanges();

你不需要担心事务的问题,context.SubmitChanges在执行时会自动创建本地数据库事务,来保证操作的完整。关于事务的问题,我们在“LINQ那些事(3)”中会有详细讨论。

查询

先看看下面这段代码

var context = GenerateContext();
context.Log = Console.Out;// 查询publisher对象
Console.WriteLine("Querying publisher");
Publisher publisher = context.Publishers.Where(
p => p.PublisherID == new Guid("ae825c5f-465d-4eb5-a2bb-cc1aeb5edb7d")).Single();Console.WriteLine("Querying books")
// 当调用publisher.Books.GetEnumerator()时,执行book对象的查询
foreach (Book book in publisher.Books)
{
Console.WriteLine(book.Title);
}

在默认情况下,DataContext并不会加载Assocation对象(EntitySet<T>或EntityRef<T>),当Assocation对象需要被访问时才会执行数据库查询,这就是所谓的lazy-loading。LINQ2SQL的Layz-loading的实现与IEnumerable<T>的deferred query execution是一样的,有兴趣可以看看EntitySet<T>.GetEnumerator或EntityRef<T>.Entity.Getter代码。

Lazy-loading的好处是避免了不必要的查询,但是在某些场合确定Assocation对象都应该加载时,我们可以设置DataContext. LoadOption来指定Assocation对象的加载:

DataLoadOptions option = new DataLoadOptions();
option.LoadWith<Publisher>(p => p.Books);
context.LoadOptions = option;

总结:本节讨论了如何使用LINQ2SQL来进行简单对象和涉及Association的对象的CRUD操作。示例代码段在只涉及一个DataContext对象或在单线程的情况下都可以正确运行,但是当涉及多个DataContext或并发访问的情况的下会怎么样呢?这是我们接下来要讨论的。

链接

LINQ那些事(总)

1、 LINQ那些事儿(1)- 定义从关系数据库到Entity Class的映射

2、 LINQ那些事儿(2)- 简单对象的CRUD操作和Association的级联操作

3、 LINQ那些事儿(3)- 事务和并发冲突处理

4、 LINQ那些事儿(4)- Query Expression和Query Operator

5、 LINQ那些事儿(5)- 动态查询

6、 LINQ那些事儿(6)- DataContext的对象生命周期管理

7、 LINQ那些事儿(7)- 通过自定义IEnumerable<T>来扩展LINQ

8、LINQ那些事儿(8)- 通过自定义IQueryable<T>和IQueryableProvider来扩展LINQ

转载于:https://www.cnblogs.com/chwkai/archive/2009/12/31/linq_crud.html

LINQ那些事儿(2)- 简单对象的CRUD操作和Association的级联操作相关推荐

  1. 数据库级联操作mysql_数据库进阶实践-级联操作 --

    数据库进阶实践 级联操作 Cascade意为"级联操作",就是在操作一个对象的同时,对相关的对象也执行某些操作.我们通过一个Post模型和Comment模型来演示级联操作,分别表示 ...

  2. MyBatis-Plus(八)Mapper的CRUD接口5:增删改操作

    Mapper的CRUD接口5:增删改操作 1.新增数据 insert 方法可以将一个实体对象插入到对应的数据表中: @RestController public class HelloControll ...

  3. jpa级联添加_JPA中的一对多双向关联与级联操作

    学习Spring有两周时间了 , 个人觉得服务端主要实现的是数据关系的维护和数据结构的制定 , 以及由业务需求产生的CRUD , 只要保证对前端提供的接口稳定高效响应 , 具体的前端实现完全不关心. ...

  4. java8 流操作_java8中的流操作

    Stream 流是 Java 8 新提供给开发者的一组操作集合的 API,将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选.排序.聚合等.元素流在管道中经过 ...

  5. 【Android 安全】DEX 加密 ( 代理 Application 开发 | 解压 apk 文件 | 判定是否是第一次启动 | 递归删除文件操作 | 解压 Zip 文件操作 )

    文章目录 一.判定是否是第一次启动 二.递归删除文件操作 三.解压 Zip 文件操作 四.解压操作相关代码 参考博客 : [Android 安全]DEX 加密 ( 常用 Android 反编译工具 | ...

  6. Docker常用命令操作——1)、镜像操作;2)、容器操作

    Docker常用命令&操作 1).镜像操作 https://hub.docker.com/ 操作 命令 说明 检索 docker search 关键字 eg:docker search red ...

  7. mysql外键约束语句级连_mysql之外键约束(级联操作等) 父表子表

    不理解的地方标注问号. 网上不同的博客讲的,之间似乎有些矛盾,求推荐好书. 写得不好请指出错误. 父表和子表 当两个表建立一对多关系的时候,"一"的那一端是父表,"多&q ...

  8. axure 如何设置选项联动_Axure下拉框级联操作

    现实生活中有很多的下拉框是级联操作的,即因为第一个下拉框的选择,影响到后面的下拉框的选择的列表的数据.或许在代码中,这些操作相对比较简单,通过前一个下拉框的选择项来控制后一个下拉框的数据的动态添加.那 ...

  9. 多重连弹の多层级联 下拉框/查找框级联操作

    为什么80%的码农都做不了架构师?>>>    省市区级联,需求背景就不多说了,几乎是管理系统必备的一个功能,对于大部分初级开发者来说,做这种功能还是比较繁琐,又要写后端又要写前端. ...

最新文章

  1. ftp 的三种数据传输模式
  2. Spartan-6的SelectIO资源
  3. 在CMD窗口连接到Mysql
  4. 用神经网络模拟分子:钾的卤化物
  5. DevExpress组件之——TreeList组件
  6. python2.7安装matplotlib_Python安装Numpy和matplotlib
  7. 安卓入门系列-02创建一个项目
  8. 哈尔滨工业大学计算机培养计划,哈工大计算机科学与技术专业本科生培养方案.docx...
  9. lua split实现(lua程序设计10.6练习10.1题)
  10. linux图形界面为英文,Linux下“英文控制台 中文图形界面”的实现
  11. 编译vuejs html,VueJs(2)---VueJs开发环境的搭建和讲解index.html如何被渲染
  12. 把CheckBox的方块换成图片或其他
  13. wav格式的音频文件 16位转化成8位的
  14. 2021年4月蓝桥杯软件类省赛:题目+解析(完整版)
  15. Windows通过IP地址向对方发送信息
  16. [转]RDL(C) Report Design Step by Step 3: Mail Label
  17. DHCP 协议(一)
  18. 旋转卡壳算法(转载)
  19. vue push html,html5 - Vue 2.0 javaScript 数组循环push json 对象问题
  20. jsp标签与指令总结

热门文章

  1. opencv图像边界的填充
  2. mse函数(均方误差函数)
  3. linux下mkdir头文件_整理Linux下gcc编译中关于头文件与库文件搜索路径相关问题
  4. 第三章:3.0 本章内容介绍
  5. 第二十三讲 解一阶微分方程组
  6. Session对象的生命周期
  7. .Net NPOI 根据excel模板导出excel、直接生成excel
  8. elasticsearch安装kibana插件
  9. Linux CentOS7.0下JAVA安装和配置环境变量
  10. Design verification经验总结