一.摘要
第一篇文章我简要介绍了项目的设计框架和LINQ实现思想. 本篇文章将是最实际和具有技巧性的地方, 就是如何创建LINQ TO SQL 的模型对象.
二.
前言1.LINQ与LINQ TO SQL
姜敏同学提醒我要注意LINQ TO SQL和LINQ的不同.的确这两者就类似C#和.NET. 老赵曾写文章特别强调过两者的不同.这里再简单提一下.
LINQ是Language-Integrated Query的缩写, 翻译后是"集成语言查询", 我将LINQ看做是一种查询框架, 拥有自己的特定语法. 只要对象实现了LINQ框架所需要的接口, 就可以使用LINQ语法进行查询.比如:
Code
var query =
from tagCategory in dc.TagCategory
where tagCategory.pkid == tagCategoryId
select tagCategory
LINQ TO SQL 是一个LINQ Provider, 能够实现轻量级的ORM, ORM的作用是将数据库中的表和Model模型做映射, 比如Java中的Hiberate(.NET中也有NHiberate). LINQ TO SQL让我们可以使用LINQ的语言操作Model对象, 完成对数据库的CRUD操作.
为何我们可以使用LINQ语言查询一个Object? 因为有LINQ TO Object.
为何我们可以使用LINQ语言查询对象操作数据库? 因为我们有LINQ TO SQL.
2.LINQ TO SQL 的Model对象
传统的Model对象是一种信息模型, Model类一般不包含任何的方法, 只包含属性.要描述一个现实世界Student, 首先需要一个Student的Model类, 比如类名就叫做Student, 用来保存每一个Student特有的信息, 比如名字. 然后将其具有的行为在业务逻辑层描述, 比如在业务逻辑层创建一个StudentBL类, 为其添加一个Walk()方法. 现在比较流行使用业务模型设计系统, 业务模型会将信息和行为抽象成一个Student角色.但是我还很少使用.
使用LINQ TO SQL, 我们能将传统意义上的Model模型的某一个属性, 比如Student类的Name属性与数据库Student表的Name字段建立映射关系, 这就是ORM: 对象Object 关系Relational 映射Mapping 的含义. 有了ORM, 当我们修改Student的Name时,将自动修改数据库中的数据. 我们再也看不到SQL了, 系统中统统都是操作对象.
LINQ TO SQL 提供了可视化设计工具"O/R 设计器"和命令行工具SqlMetal.exe 为数据库中的表自动生成Model类代码. 但是默认生成的代码只能做做简单的Demo例子, 在实际应用中有很多问题和需要修改的地方.下面将我创建一个Model对象的的"最佳实践"拿出来和大家分享.
三. 使用工具建立Model类
在架构上我将Model类横向切割为一层, 纵向将每个业务线切割为一个项目.比如Tag系统的模型层为: Com.Elong.Model.Tag
每个项目首先都要为每个表创建Model类, 这一步我会使用O/R设计器的可视化设计.下面简单介绍一下步骤.
1.使用 O/R 设计器
在项目中添加新项是, 我们选择"LINQ TO SQL类",如下图:
我们会在项目中添加TagDataContext.dbml文件, 展开此文件的"+"会发现其包含两个子文件: TagDataContext.dbml.layout以及TagDataContext.design.cs
其中 TagDataContext.design.cs 中保存我们的DataContext类和所有表的Model类代码. TagDataContext.dbml.layout保存的是可视化设计的一些信息.
双击 TagDataContext.dbml 文件会进入可视化设计阶段. 使用O/R设计器十分简单, 在此不做介绍.想学习的可以参考MSDN或者一些前辈的系列教程,无非就是拖拖拽拽的工作.下面是一张O/R设计器截图:
提供下面几个技巧和经验:
1.如果想自动创建数据库中两个表的关系, 需要将这两个表同时拖出.
2.单击设计器空白处,查看属性面板, 有很多属性可以在这里修改:
最有用的上下文命名空间 和 实体命名空间. 上下文命名空间是DataContext类的命名空间, 我通常将其放置在DataAccess层中.实体命名空间是所有Model类所在的命名空间, 我将其放置在Model层中.
3.任何在可视化设计中的修改, 都会造成 .design.cs 文件重写, 所以现阶段不要手工对此文件做修改. 因为一旦作了修改将不能再使用O/R 设计器.
4.O/R 设计器允许我们创建一个不会重写的类来扩成自动生成的代码,创建方法是在O/R设计器的空白处点右键, 在弹出菜单中选择"查看代码",如图:
会在.dbml文件中添加一个.cs文件:
请一定要创建这个文件,因为以后我会将Model类的方法创建在这个文件中.
四.使用SqlMetal.exe工具
上一章中已经提到过SqlMetal.exe,它是一个命令行工具, 需要从Visual Studio的命令行中使用.也会生成DataContext和Model类的代码.比如:
Code
Sqlmetal /conn:"uid=****;pwd=****;initial catalog=DataBaseName; data source=192.168.0.1; Connect Timeout=900; Connection Reset=FALSE" /code:"d:\DB.cs"
DB.CS中会有包含了是数据库所有表的DataContext以及每一张表的Model类.
一旦我们对可视化设计生成的.Design.cs文件作了修改, 比如添加了注释, 那么请不要再使用 O/R 设计器进行可视化的更改.正确的做法是手动的修改.Design.cs中的代码, 对于新加表等工作量比较大的修改, 可以先使用SqlMetal.exe生成表对应的Model类的初始代码, 将其Copy到.Design.cs中,然后再自行修改.
五.修改 TagDataContext.Design.cs 文件
在Design.cs中, 我们要做下面几项修改:
1.修改Model类名
修改Model类名称,以及Model类Table特性的值,去掉其中的"用户."前缀.添加注释.下面是一个例子.
修改前:
Code
[Table(Name = "dbo.T_Activity")]
public partial class T_Activity
修改后:
Code
///
/// 活动表.保存各种活动信息
///
[Table(Name = "T_Activity")]
public partial class Activity
2. 添加所有属性的默认值和注释.
以ActivityName属性为例.
添加默认值:
Code
private string _ActivityName = string.Empty;
添加注释:
Code
/// /// 活动名称
/// [Column(Storage = "_ActivityName", DbType = "NVarChar(200) NOT NULL", CanBeNull = false)]
public string ActivityName
3.在主键列的Column特性上添加IsVersion属性,值为true
比如:
Code
/// <summary>/// 自增主键/// </summary>
[Column(Storage = "_pkid", AutoSync = AutoSync.OnInsert, DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true, IsVersion = true)]
public int pkid
这一条相当重要.否则使用LINQ会遇到很多问题.当然也可以建立一个额外的TimeStamp列来用做IsVersion列,但是比较麻烦.
对于主键来说, AutoSync属性应该设置为 OnInsert, 实现的功能就是当我们将想要Insert一个对象时, 在插入前并没有对象的主键ID为null或默认值, 但是当调用DataContext完成Insert操作后, 此对象的主键ID属性会被自动被填充.
3.将使用数据库默认值的模型属性上,添加Column(IsDbGenerated=true)
比如:
Code
[Column(Storage = "_CreatedTime", DbType = "DateTime NOT NULL", IsDbGenerated=true)]
public System.DateTime CreatedTime
{ }
CreatedTime是数据库中使用getDate()在创建时写入的,我们希望使用数据库中的值.而不是在程序中更新.注意使用LINQ更新的是对象,如果使用默认的代码并且没有添加IsDbGenerated, 则数据库中的getDate()将失效.
4.修改DataContext类
如果我们添加了新的表, 除了修改.Design.cs中的Model模型类,还需要修改同样在此文件中的DataContext类.假设我们要添加一个Activity表,则需要在DataContext类中增加下面代码: