第八章 LINQ进阶
8.1 LINQ数据映射
在第四章对LINQ To SQL 的学习中,我们用到了LINQ的数据映射和DataContext类型对象。在本小节中,我们一起来学习一下LINQ将数据库中关系型数据映射为数据实体类的实现机制,以及DataContext类型的日志功能和自动生成SQL语句功能,只有充分地掌握了这些
机制,才能更好地理解和使用LINQ。为了让您充分地理解这些内容,我们还是自己动手编写代码来实现数据的映射,而不是使用如第四章中的自动生成代码的方法,但在本小节中仍然会使用到第四章中的OnLineStore的数据库,然后再将我们自己编写的代码与第四章LINQToSQLWebSite网站项目中的DataContext.dbml代码文件的实现情况做一个比较和分析。
8.1.1 表和实体类
首先,让我们来了解一下数据表是如何映射为一个实体类的。我们新建一个网站,命名为MoreLINQWebSite,在这个网站项目中我们手动地编写数据映射代码,这样更有助于我们了解其实现机制。我们在解决方案资源管理器中选择网站项目文件并添加两个类,分别命名为Category.cs和Product.cs,我们用这两个类分别作为Category表和Product表的数据实体类。
好,下面开始编码工作,我们从Category类开始。因为我们要将Category类与数据库表相互映射,因此需要为项目添加一个对System.Data.Linq.dll的引用,如图8-1,并在代码文件的开头引用System.Data.Linq.Mapping的命名空间。
做好一切的准备工作之后,我们在Category类声明的前面,加入一个[Table(Name=”Category”)]特性,如代码8-1,用以表示该类与数据库表中的Category表相映射,如果没有括号中的Name属性,LINQ会根据数据库表名和类名自动匹配,也就是说此时的数据库表名应该与类名相同。
图8-1
using System.Data.Linq.Mapping;// // 与数据库中Category表相互映射的实体类 [Table(Name="Category")] public class Category { } |
代码8-1
现在让我们来看看LINQToSQLWebSite中的表映射属性,打开LINQToSQLWebSite项目,到App_Code文件夹下DataClasses.designer.cs文件中的Category实体类声明,我们可以同样的发现一个与数据库中表的映射声明,只不过在DataClasses.designer.cs文件中的这些代码都是自动生成的。
采用同样的方法,可以将数据库中Product表映射到Product类,我们将它作为练习留给读者。
8.1.2 字段和属性
声明了数据库表的映射关系后,我们需要将数据库中的数据字段映射到类的属性,如代码8-2,在Category数据表中有两个字段,分别是主键CategoryID和Name,与之对应,我们为Category实体类声明了 CategoryID和Name属性。
/// <summary> /// 与数据库中Category表相互映射的实体类 /// </summary> [Table(Name="Category")] public class Category { //CategoryID属性 [Column(IsPrimaryKey=true,Name="CategoryID",DbType="Int NOT NULL")] public int CategoryID { get; set; } //Category Name属性 [Column(Name = "Name", DbType = "VarChar(100) NOT NULL", CanBeNull = false)] public string Name { get; set; } } |
代码8-2
从代码8-2中我们可以看到,将类的属性添加一个[Column]特性,用来表示该数据与数据表中的列字段相匹配。在CategoryID属性的声明时我们使用了C#3.0中的自动属性新特性,并为[Column]特性添加了IsPrimaryKey属性,用来表明CategoryID属性在数据表中是一个主键,因此Category对象将CategoryID属性作为其身份的唯一标识,接着为[Column]添加了Name属性表示数据字段的名称,DbType属性用于标识字段在数据库中的数据类型,在这里的“Int NOT NULL”表明CategoryID字段是一个INT类型的非空字段。在Category类型的Name属性的[Column]特性中我们可以看到一个CanBeNull属性,它用来表明这个字段在数据库表中是否允许为空,在这里的设置为false,即表示该字段不允许为空。
在LINQToSQLWebSite网站项目的DataClasses.designer.cs文件中,我们可以看到这里的Category类并没有使用自动属性特性,而是定义了一些私有字段,并用对应的公共属性去访问,在代码中我们可以看到Visual Studio自动生成的代码与我们刚刚编写的代码基本没有区别,只是更加的复杂,自然地使得自动生成的LINQ To SQL实体类具有非常强大的功能。
采用同样的类属性与数据库字段映射方法,我们可以同样地为Product添加映射属性,我们也将它作为练习留给读者。
8.1.3 实体类关联
在数据库设计时,设计人员常常应用“三个范式”将数据表用外键的形式关联起来。OnLineStore数据库中的Category表的CategoryID主键就作为Product表的外键使这两个数据表相互关联,并且它们是一个一对多(one:many)的关系,即一条Category数据可以对应多个Product数据,因此可以通过CategoryID到多个同一种商品类型的产品。
在LINQ To SQL的实体类之间也可以实现这样的关联。根据数据库表之间的关联,我们可以在Category类中设计EntitySet类型的泛型集合,用于存放与之对应的Product类型对象,如代码8-3,在Product属性前用[Associtation]特性表明这是一个将Product类型与Category类型关联起来的属性集合,其中的OtherKey属性表明是按照“CategoryID”字段来关联,这样的方式与数据库表中的外键相同,在这里我们用到的是一项叫做对象树(Object Trees)的方法。
using System.Data.Linq.Mapping; using System.Data.Linq;// 需要添加 //将Category表与Product表关联起来 [Association(Name = 制作查询类小程序"Category_Product", OtherKey = "CategoryID")] public EntitySet<Product> Product { get; set; } |
代码8-3
在声明了EntitySet<Product>类型的Product属性后,我们就可以根据Category对象来查相应的Product对象集合。
上述这些映射工作虽然可以依靠手工编写代码来完成,就像我们刚刚所做的这些工作这样,但是这无疑给开发人员带来了额外的工作,相反,使用LINQ To SQL实体类,即正如第四章中所介绍的DataClasses.dbml文件中所做的工作,可以自动地生成关系型数据到实体类映射的代码,而且还提供了更为丰富的功能,为我们提供了最大限度的便利。
8.1.4 数据访问
在做好了所有的数据实体类代码编写之后,我们来了解一下LINQ To SQL是如何通过DataContext类型实现数据访问的。我们可以把DataContext看作是LINQ To SQL的入口点和连接面向对象世界与关系型数据世界的一座桥梁,DataContext类型对象可以为我们做许多的工作,包括将LINQ查询表达式翻译为SQL语句、将数据从数据库中取出并返回以及将数据实体的更新写入数据库等等。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论