Linq(集成语言查询)在与数据库交互增删改查中使用的非常多。Linq分为Linq to SQL(已经过时)、Linq to EF、Linq to XML等多种类型。LInq to EF 是针对EF实体框架而构建的。使用EF(实体框架)可以及其方便地创建和修改SQL数据库,它封装了繁琐的SQL代码,通过数据库和对象之间的映射,让程序员可以完全按照面向对象的思路使用linq语句操纵数据库中的数据。本文就使用LInq to EF做一下基本的增删改查。不对之处请各位高手拍砖指教。
本次的增删改查采用EF三种设计模式中的DBFirst设计模式(EF中的DBFirst实例)。下面进行基本的增删改查(列出的所有代码已经过测试)。
一、添加
Student1 str = new Student1(); //新建实例
str.Sno = Txtno.Text; //为该实例的各个属性赋值
str.Sname = Txtname.Text;
str.Ssex = Convert.ToInt16(Txtsex.Text);
str.Sphone = Txtphone.Text;
str.Saddress = Txtaddress.Text;
dbcontext.Student1.AddObject(str); //添加到对象上下文中
dbcontext.SaveChanges(); //保存修改
//第二种方式
//{
//dbcontext.Student1.Attach(str);
//dbcontext.ObjectStateManager.ChangeObjectState(str,EntityState.Added);
//dbcontext.SaveChanges();
//}
//新建实例简单方法
//Student1 str = new Student1()
//{
// Sno = Txtno.Text,
// Sname =Txtname.Text,
// Ssex =Convert.ToInt16(Txtsex.Text),
// Saddress=Txtaddress.Text,
// Sphone= Txtphone.Text
//};
总结:第一种方法中使用AddObject()方法添加实体到当前上下文中包含了两个操作:
(1)把该实体附加到上下文中
(2)修改实体的状态为添加
第二种方法是第一种方法的展开操作而已,两种方法都OK。
在这里,我们可以简单的记上面的方法:上下文=数据库、实体名=表中。只是为了简单记而已,实际上两者并不等价。
二、查询
#region 简单的无where的查询 Linq表达式
var resultt = from c in dbcontext.Student1 select c;
if (resultt == null) //查询结果不存在
{
//
}
else
{
//
}
#endregion
#region 简单的无where的查询 Lamada表达式
var first = dbcontext.Student1.FirstOrDefault();//查询出第一条数据 如果不存在则输出默认值
#endregion
#region 带where的Linq 查询
var resultWhere = from c in dbcontext.Student1 where c.Sno == TextBox1.Text select c;
if (resultWhere == null) //查询结果不存在
{
//
}
else
{
//
}
#endregion
#region 带Where的lamada查询
var result1 = dbcontext.Student1.Where(s => s.Sno == TextBox1.Text).FirstOrDefault(); //后面的FirstOrDefault()如果使用的是主键查询可以省略。
//FirstOrDefault 默认的就是查询第一条记录,否则为默认
var result2 = dbcontext.Student1.FirstOrDefault(s => s.Sno == TextBox1.Text);//两种方式都可以
#endregion
总结:通过Linq或Lambda表达式查询出来的结果都是实现了IQueryable<T>接口的实体集。
关于IQueryable<T>接口我们有必要详细说一下,在该接口内部只有这么几行简单的代码。
public interface IQueryable : IEnumerable
{
// 摘要:
// 获取在执行与 System.Linq.IQueryable 的此实例关联的表达式树时返回的元素的类型。
//
// 返回结果:
// 一个 System.Type,表示在执行与之关联的表达式树时返回的元素的类型。
Type ElementType { get; }
//
// 摘要:
// 获取与 System.Linq.IQueryable 的实例关联的表达式树。
//
// 返回结果:
// 与 System.Linq.IQueryable 的此实例关联的 System.Linq.Expressions.Expression。
Expression Expression { get; }
//
// 摘要:
// 获取与此数据源关联的查询提供程序。
//
// 返回结果:
// 与此数据源关联的 System.Linq.IQueryProvider。
IQueryProvider Provider { get; }
}
虽然通过上面的注释大家也都了解的差不多了,但是,我还是想再唠叨一下。当一个查询请求过来时,会先有Provider执行查询表达式(Expression),接着才会生成sql脚本,到数据库中去查询数据。注意,前面的一句话到数据库中查询数据是不准确的。为什么这么说呢?延迟加载,这就是原因。IQueryable是离线型的集合,真正sql语句的执行是在数据真正用到的时候才会执行。
三、修改
//Student1 str = new Student1();//首先创建一个实体类
Student1 str = (from c in dbcontext.Student1 where c.Sno == Txtno.Text select c).SingleOrDefault<Student1>();//本次查询是针对主键进行的查询,///查询结果只有一个或者为空,也可以设置其他查询条件,进行多个数据的修改操作
if (str == null)
{
Label1.Text = "数据库中不存在该用户!";
return;
}
else
{
str.Sno = Txtno.Text;
str.Sname = Txtname.Text;
str.Ssex = Convert.ToInt16(Txtsex.Text);
str.Sphone = Txtphone.Text;
str.Saddress = Txtaddress.Text;
//dbcontext.Student1.Attach(str); //将该实体类附加到对象上下文中
dbcontext.ObjectStateManager.ChangeObjectState(str, EntityState.Modified);//修改对应实体的的状态
dbcontext.SaveChanges(); //保存修改
}
四、删除
ObjectQuery<Student1> st = dbcontext.Student1;//在此使用的是主键查询,也可以使用其他字段查询,删除多个数据
IQueryable<Student1> str =from c in dbcontext.Student1 where c.Sno == Txtno.Text select c;
Student1 st1 = (from c in dbcontext.Student1 where c.Sno == Txtno.Text select c).SingleOrDefault<Student1>();
if (st1 == null)
{
Label1.Text = "数据库中不存在该用户!";
return;
}
else
{
dbcontext.ObjectStateManager.ChangeObjectState(st1, EntityState.Deleted);//修改对应实体的的状态
dbcontext.SaveChanges();
//也可以使用下面的方式 第二种方式比较简单
//dbcontext.Student1.DeleteObject(st1);
//dbcontext.SaveChanges();
}
五、分页查询
//要跳过多少页
int skipPage;
//每页两条数据
int countPerPage = 2;
//从跳过0页到跳过2页(输出第1-3页)
for (skipPage = 0; skipPage <= 2; skipPage++)
{
var result = dbcontext.Student1
//分页必须排序
.OrderBy(t => t.Sno)
//跳过指定页数
.Skip<Student1>(skipPage * countPerPage)
//获取条数
.Take<Student1>(countPerPage);
int count = skipPage + 1;
Response.Write("第" + count + "页:");
//输出查询结果(该页)
foreach (var item in result)
{
Response.Write("学号:" + item.Sno + ",姓名:" + item.Sname + ",性别:" + item.Ssex + "\r\n");
//Label1.Text += "学号:" + item.Sno + ",姓名:" + item.Sname + ",性别:" + item.Ssex;
//Label1.Text += "\r\n";
}
}
六、使用匿名类查询多个字段
#region
var resultt = from c in dbcontext.Student1 where c.Sname == "小意" select new { c.Sno, c.Sname, c.Ssex };
//var result=from c in dbcontext.Studnent1 where c.Sname="小意" select new {id=c.Sno,name=c.Sname,sex=c.Ssex}//也可以使用这种方式
if (resultt == null) //查询结果不存在
{
//
}
else
{
//
foreach (var item in resultt)
{
Label1.Text += "学号:" + item.Sno + "姓名:" + item.Sname + "性别:" + item.Ssex;//此时Saddress、Sphone等字段无法访问
}
}
#endregion
前面我们查询的都是整个Student对象,在实际使用过程中,我们可能只需要查询某些字段,这个时候我们就需要匿名类了。
七、防延迟加载查询
这个查询结果可以保存到服务器内存中
var result1 = (from u in dbcontext.Student1
where u.Ssex==1
select u).ToList<Student1>();
foreach (var item in result1)
{
Response.Write("学号:" + item.Sno + ",姓名:" + item.Sname + ",性别:" + item.Ssex + "\r\n");
}
上面我们介绍的一些普通的延迟查询,查询的结果都是IQueryable类型,这个类型中只放三样东西:查询表达式、元素的类型、查询的驱动。我们得到的查询结果是在我们遍历的时候才执行得到的。使用ToList()查询的时候就已经执行了查询,得到了结果,防止了延迟加载的发生。防延迟加载技术主要使用在缓存技术中。
八、总结
上面列出的增删改查有的可能不止一种实现方式,具体使用哪种方式可以根据自己的偏好,当然有时候要考虑性能,择优采用。
Linq语句不容易编写,想要编写正确的Linq语句可以借助LINQPad工具
注意:在EF 4.0 和EF4.0+版本中,上面的方法可能会有些许的变化