LINQ入门之访问数据库(插,删,改)[转]

 

      以博客园的系统为例子,既然称Linq to SQL为一个ORM框架,ORM,对象-关系 映射,既然O在前关系在后,说明O为重,关系是根据O得来的,那么我们就先新建一些Entity Object吧。在一个博客系统里最常见的就是User,Blog,Post

一个用户有且仅有一个博客,而一个博客可以有零篇或者多篇博客文章。根据这个描述我们来建立Entity

 

Step 1 建立实体对象

 

ContractedBlock.gif ExpandedBlockStart.gif User  <summary>
///  用户类
///  </summary>
public  class  User
ExpandedBlockStart.gifContractedBlock.gif
/// <summary>
        
/// 用户标识
        
/// </summary>

ExpandedSubBlockStart.gif ContractedSubBlock.gif          public  int  Id  getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 该用户对应的博客,
        
/// 一个用户有且仅有一个博客
        
/// </summary>

ExpandedSubBlockStart.gif ContractedSubBlock.gif          public  Blog Blog  getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 用户名
        
/// </summary>

ExpandedSubBlockStart.gif ContractedSubBlock.gif          public  string  UserName  getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 密码
        
/// </summary>

ExpandedSubBlockStart.gif ContractedSubBlock.gif          public  string  Password  getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 昵称
        
/// </summary>

ExpandedSubBlockStart.gif ContractedSubBlock.gif          public  string  NickName  getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 用户离开时间
        
/// </summary>

ExpandedSubBlockStart.gif ContractedSubBlock.gif          public  DateTime LeaveTime  getset; }
}
  
ContractedBlock.gif ExpandedBlockStart.gif Blog /// <summary>
    
/// 博客类
    
/// </summary>

     public  class  Blog
ExpandedBlockStart.gifContractedBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 博客标识
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public int Id getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 用户标识,和用户相关联
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public int UserId getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 博客的中文名
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public string Name getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 创建时间
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public DateTime CreateDate getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 一个博客有零篇或多篇文章
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public IList<Post> Posts getset; }
}
ContractedBlock.gif ExpandedBlockStart.gif Code /// <summary>
/// 博客文章类
/// </summary>

public  class  Post
ExpandedBlockStart.gifContractedBlock.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 文章Id
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public int Id getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 文章从属的博客
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public int BlogId getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 标题
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public string Title getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 内容
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public string Body getset; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/// <summary>
        
/// 发表时间
        
/// </summary>

ExpandedSubBlockStart.gifContractedSubBlock.gif        public DateTime CreateDate getset; }
}
我们先不要谈论这个设计是否合理,也不要谈论这三个实体是贫血模型还是充血模型。

对象建立好了,我们来建设数据库表吧:users表,blogs表,posts(为什么表都用复数?Rails里学过来的,ActiveRecord模式里,表里每条记录都对应着一个对象,所以表用复数表示,这是一种约定)

 

Step 2:创建数据库表

Users表:



Blogs 表:

Posts表:

我们注意到,用户类里的LeaveTime离开时间在数据库里并没有对应的字段,因为这个是用来临时记路用户离开离开博客园的时间的,这样可以用来做一些在线统计,所以无需持久化。

 

Step 3:建立映射

对象也有了,关系也有了,那剩下的是什么?对,就是映射,我们怎样将对象映射到数据库表上?

我们从最简单的Post开始吧:

///  <summary>
    
///  博客文章类
    
///  这个类和数据库里的posts表对应,由于
    
///  类名和表名不一样,所以需要显式的指明Table特性的Name属性
    
///  如果是一致的则无需指明了
    
///  </summary>
    [Table(Name = " posts " )]
    
public  class  Post
    {
        
///  <summary>
        
///  文章Id
        
///  这个对应posts表里的postid
        
///  这个字段还是一个主键,所以Column特性的IsPrimaryKey属性为true
        
///  </summary>
        [Column(Name = " postid " ,IsPrimaryKey = true )]
        
public  int  Id {  get set ; }
        
///  <summary>
        
///  文章从属的博客
        
///  这个对应着表里的blogid,名字一样所以只需要加个Column特性就可以了
        
///  下面几个也是一样的意思
        
///  </summary>
        [Column]
        
public  int  BlogId {  get set ; }
        
///  <summary>
        
///  标题
        
///  </summary>
        [Column]
        
public  string  Title {  get set ; }
        
///  <summary>
        
///  内容
        
///  </summary>
        [Column]
        
public  string  Body {  get set ; }
        
///  <summary>
        
///  发表时间
        
///  </summary>
        [Column]
        
public  DateTime CreateDate {  get set ; }
}
仔细看看注释里面的说明,很简单吧,在类上面加Table 特性,属性上加Column 特性。

映射建完了,我们可以施加一些操作了。

在上一篇文章里介绍了,Linq to SQL的入口点是DataContext类,这个类主要做这么几件事情:

将我们用C#写的这个查询翻译成SQL语句,当然也并不是他全权负责翻译工作。

执行查询

连接的管理,这样我们就不用写啥Connection了啊,也不用担心数据库的连接和关闭的问题。

 

Step 4:执行查询

那我们就首先实例化一个DataContext类吧(为了好测试,使用一个控制台程序)

DataContext dbContext  =  new  DataContext(ConfigurationManager.ConnectionStrings[ " CnBlogs " ].ConnectionString);
从这里可以看出,DataContext 需要一个连接字符串,在DataContext 里,我们打交道最多的就是GetTable<TEntity>() 方法,这里的TEntity 就是我们上面的那个Post 了,带有映射的实体,这个方法返回一个Table<TEntity> 对象:
Table < TEntity >  posts  =  dbContext.GetTable < Post > ();
实际上,Table<TEntity> 实现了IEnumerable<TEntity> 接口,那这里实际上是返回了一个IEnumerable<Post> 系列,那我们可以对posts 进行遍历了:
foreach (var post  in  posts)
       Console.WriteLine(post.Title);
实际上,如果光返回一个Table<TEntity> ,而不在上面施加任何的操作,遍历的时候是返回整个表的数据,在上一篇我还提到,为了跟踪,我们最好将dbContext.Log 给显示出来。如果你添加了下面这行代码:
dbContext.Log  =  Console.Out;
( 对于这行代码,如果你使用的是控制台程序,那么输出就会显示在命令窗口里,如果你用的是WinForm 程序调试,那么输出会显示在VS output 窗口里)

那你将会从控制台里得到下面的东东:


这就是Linq 为你生成的SQL 语句,是不在是比你写的还标准啊,呵呵。

当然,我们常常做的肯定不是像上面这样的全查询,我们还要附加一些条件的。

上一篇还提到过:由于Table<TEntity>实现了IEnumerable<TEntity>接口,那么所有的查询表达式都可以在这里使用了,这样你先前在Linq to Objects里学到东西现在又有了新的用途了:

比如我们可以对BlogId做筛选:

var posts  =  from post  in  dbContext.GetTable < Post > ()
         
where  post.BlogId  ==  2
         select post;
(PS :我在写Linq 语法的时候,因为Linq 的风格太像SQL 语句了,所以一些地方比如 == 我老写成= ,而&& 经常写成”and” ,希望大家不要烦我这样的低级错误,呵呵)

看看这次生成的SQL语句:

可以看到生成的SQL语句对blogid做了筛选,而且值得庆祝的是,Linq to SQL为我们生成的SQL语句还使用的是参数,她并不是仅仅将数值和语句组合在一起。关于使用参数而不是拼凑起来的SQL语句的好处在这里啰嗦两句,主要有两点:

这样可以有效的SQL注入攻击,这个hack手段曾经让很多网站吃尽了苦头。

使用参数可以利用Sql ServerSQL语句的缓存和预编译作用,因为使用参数的SQL语句可能多次用到,而拼凑起来的SQL语句却和特定的查询有关。

这样的筛选还不能体现出Linq的智能了,请再看这个:

var posts  =  from post  in  dbContext.GetTable < Post > ()
         
where  post.Title.StartsWith( " y " )
         select post;

面对这样的一个Linq 查询,Linq to SQL 居然知道将它翻译成LIKE 子句,从上图倒数第二行最后中括号里面的东西可以看出,Linq to SQL 还知道将传入的参数设置为y% ,我不得不惊叹:太强大了。

但是不是所有的C#的方法都可以使用呢?答案是否定的。比如:

var posts  =  from post  in  dbContext.GetTable < Post > ()
         
where  post.Title.StartsWith( " y " )
         select post.CreateDate.ToString(
" yyyy-MM-dd " );
我想对最后查出来的文章的创建时间做个格式化,居然报错了,说不支持这种“翻译”。那看来每次我们做查询的时候是要先try 一下。

上面只是做了筛选的实例,你还可以去尝试一下排序和分组,这个和Linq to Objects里的用法是一样的,你可以到前面的文章里复习一下。

 

Step 5:插入对象

本系列的文章到现在为止都是在介绍查询,难道Linq to SQL只能做查询么?不能向数据库添加数据?,肯定不是的:

Table < Post >  posts  =  dbContext.GetTable < Post > ();
// 先实例化一个新的要插入的对象
Post post  =  new  Post();
post.BlogId 
=  2 ;
post.Title 
=  " test " ;
post.Body 
=  " test,test,test,test " ;
post.CreateDate 
=  DateTime.Now;
// 调用Table<TEntity>的InsertOnSubmit方法
posts.InsertOnSubmit(post);
// 把改变提交到数据库,这个时候才真正执行了
dbContext.SubmitChanges();
// 提交修改后,你就可以查询新插入的post的Id了
Console.WriteLine(post.Id);
生成的SQL 语句:

一个简单的不能再简单的insert into语句,加上一条返回新插入记录的标识值的语句。

如果你按照本文所说的一步步往下来,在执行上面的插入的时候肯定会碰到异常,这是因为,Id对应的数据表字段postid是该表的主键,你不应该在插入的时候赋值,有人说我实例化对象的时候确实没有给postId属性赋值啊,但是.net会在后台为我们将Id赋值为0,所以你要对映射对象做一下修改:

[Column(Name = " postid " ,IsPrimaryKey = true ,IsDbGenerated = true )]
public  int  Id {  get set ; }
不仅仅数据表的主键要加这个属性,如果对于那些在数据库里设置了默认值的,你并不像用程序插入的时候,你也得使用,比如这里的CreateDate

 

Step 6:更新数据

可以插入肯定就可以更新了,下面就来看看如何更新呢:

做更新的时候,你首先得从数据库查询出该对象,然后对该对象的属性进行修改,最后更新到数据库:

var posts  =  from post  in  dbContext.GetTable < Post > ()
        
where  post.BlogId  ==  2
        select post;
foreach  (var post  in  posts)
     post.BlogId 
=  5 ;

dbContext.SubmitChanges();
Linq to SQL 也会自动的帮你生成Update 语句了。

有了插入,更新,查询就差一个Delete CURD就全了,对于delete更简单了,你只要调用Table<TEntity>DeleteOnSubmit方法就行了,这里就不再详述。

 

 

转载于:https://www.cnblogs.com/winnxm/archive/2008/11/14/1333396.html

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值