EntityFramework快速入门

ADO.NET Entity Framework快速入门

作者:胡文俊

EntityFramework是一个ORM框架,是linq to sql 的升级版本,linq tosql 微软已经不再更新。与linq to sql最大的区别是 linq to sql 只支持sqlserver.而 EntityFramework支持各种数据库。

1.      模型构建

EF 的模型构建有三种方式:分别为 Database First(逆向工程) ,Model First (正向工程1),Code First. (正向工程2)

我们只学习Database First。如需研究自行学习。数据仍为 hibernate中的那个数据库

首先确认vs是否带有EntityFramework框架。

         新建一个控制台工程。在解决方案——工程名右键

查看是否存在 ADO.NET 实体数据模型。如果有请略过。

如果没有,进行如下操作。

指令:Install-Package  EntityFramework

1.模型构建

请确保数据库sqlserver上有salary数据库

新建一个控制台工程,右键-》添加-》新建项-》ADO.NET 实体数据模型

选择从数据库生成,点击下一步。新建连接

点击测试连接成功则点击确定。失败请自行检查。

修改圈圈内的名字。此名字为此数据库的上下文类或者叫实体容器。之后的数据库增删改查均需要此类。下一步。

勾选所需的表。EF会自动生成对应的模型类。

此时可看到映射已经完成。属性名或类名如需修改可以直接在此设计器中完成。如需修改类名修改完毕请记得重新生成项目。

切记不要直接在类文件中修改。否则vs将无法进行联动更新,而且更新模型修改将会被覆盖。

打开所有折叠。可看到Model1.tt下就是我们的实体类。而实体容器就为SalaryDbContext.

Model1.edmx在默认情况下打开是打开设计器。实际上它是一个xml文件。我们在此文件上右键-》打开方式  选择xml。

SSDL定义了数据库中表的相关字段类型

CSDL定义了实体类的相关属性类型

C/Smapping  显然就是定义了上面两个的映射关系了

模型设计器中可以看到每个模型有属性和导航属性。属性是指数据库中对应的列名的实体属性。而导航属性是由外键生成的实体关联对象。我们将类名大写.

从此源码可以发现  SalaryDbContext中有着我们之前选择的三张表所对应的的实体类集合。

至此。模型的构建就讲述完毕。

 

2.增删改查样例

1)添加(观察区别)

 public void addTeahcer(Teacherinfo teacher){

  SalaryDbContext context = new SalaryDbContext();

   context.teacherinfos.Add(teacher);

   context.SaveChanges();

   context.Dispose();

      }

 public void addFeature(Feature feature)

        {

     SalaryDbContext context = new SalaryDbContext();

     context.features.Add(fea);

     context.SaveChanges();

     context.Dispose();

 }

2)删除

  public void delete(Teacherinfo teacher)

   {

       SalaryDbContext context = new SalaryDbContext();

       teacher = context.teacherinfos.Find(teacher.tno);

       context.teacherinfos.Remove(teacher);

       context.SaveChanges();

   }

或者可以这样

   public void delete2(Teacherinfo teacher)

   {

 SalaryDbContext context = new SalaryDbContext();

 context.Entry(teacher).State = EntityState.Deleted;//将对象标记为删除状态

  context.SaveChanges();

   }

 

3)更新

public void update(Teacherinfo teacher){

 SalaryDbContext context = new SalaryDbContext();

 //context.teacherinfos.Attach(teacher);

 context.Entry(teacher).State = EntityState.Modified;//告诉EF它是一个修改对象

 context.SaveChanges();

 context.Dispose();

 }

也可以这样更新

  public void update2(Teacherinfo teacher)

  {

    SalaryDbContext context = new SalaryDbContext();

    var t = context.teacherinfos.Find(teacher.tno);

    t.title = "超级讲师";

    context.SaveChanges();

  }

4)查询

 public Teacherinfo query(Object teacherid)

{

   SalaryDbContext context = new SalaryDbContext();

        Teacherinfo teacher = context.teacherinfos.Find(teacherid); //根据主键正在tercherinfos中找到对应的对象

   context.Dispose();

   return teacher;

 }

或者可以这样 linq to entity

 public Teacherinfo query1(Object teacherid)

  {

  String tno = (String)teacherid;

  SalaryDbContext context = new SalaryDbContext();

  Teacherinfo teacher = (from t in context.teacherinfos where t.tno==tno                select t).Single()  ;//根据主键正在tercherinfos中找到对应的对象

     context.Dispose();

      return teacher;

  }

又或者结合lambda

 public Teacherinfo query2(Object teacherid)

 {

  String tno = (String)teacherid;

  SalaryDbContext context = new SalaryDbContext();

Teacherinfo teacher=  context.teacherinfos.Where(t => t.tno == tno).Single();

 context.Dispose();

 return teacher;

}

返回对象集合

 public List<Teacherinfo> queryAll()

 {

  SalaryDbContext context = new SalaryDbContext();

  List<Teacherinfo> teachers = context.teacherinfos.ToList();

  return teachers;

 }

根据条件获取满足的对象集:

  public List<Teacherinfo> querywith()

 {

   SalaryDbContext context = new SalaryDbContext();

 

 var result = from teacher in context.teacherinfos where teacher.sex == "女" orderby teacher.teachername descending select teacher;

   List<Teacherinfo> teachers = result.ToList();

   return teachers;

 }

1)分页查询;

 public List<Teacherinfo> querywithpage()

 {

   SalaryDbContext context = new SalaryDbContext();

   var result = (from teacher in context.teacherinfos orderby teacher.tno select teacher).Skip(0).Take(5); //表示从结果集的第0个对象开始,包括自己往后的五个对象一起返回

  List<Teacherinfo> teachers = result.ToList();

  return teachers;

}

2)联合查询

,如果我们需求为 给指定的教师编号  打印出 教师名称 教师的特征名  和教师该特征的特征值。此时我们需要查询三张表。而DbContext默认为开启懒加载。故在dispose方法调用完毕之后将无法在进行数据库的查询。如果急切的要求立即获取数据。则关闭懒加载。并将所有数据准备好。如果只是使用Teacherinfo teacher = (from t in context.teacherinfos.Include("teacherfeature"where t.tno == tno select t).Single();只是寻找了两张表 所以无法满足我们的需要。

 

  public Teacherinfo query1(Object teacherid)

  {

 String tno = (String)teacherid;

 SalaryDbContext context = new SalaryDbContext();

 context.Configuration.LazyLoadingEnabled = false;//关闭懒加载

   Teacherinfo teacher = (from t in context.teacherinfos

                where t.tno == tno select t).Single();//根据主键正在tercherinfos中找到对应的对象        

  List<TeacherFeature> tfs =(  from tf in context.teacherfeatures.Include("feature").Include("teacherinfo"where tf.tno == tno select tf).ToList();// include可以在在查询数据库时将导航属性一并加载

 teacher.teacherfeature = tfs;

 context.Dispose();

 return teacher;

 }

3).EF调用存储过程

1假如我们需要调用一个存储过程获取teacherinfo表中的记录条数,存储过程代码如下:

create proc getCount as

begin

select COUNT(*) from teacherinfo

end

在模型设计器的空白地方点击 从数据库更新模型

这里可以看到我们刚刚写的存储过程已经检测到了,点击完成。

此时在模型浏览器里面可以看到 此存储过程已经导入模型。

并且函数导入下也有了该存储过程的映射,我们双击此项。

,此时可以看到对应的映射了。函数导入名称就是我们在前面提到的上下文中直接调用的方法名称,我们可以修改名称。也可以修改返回值。由我们所写的存储过程可知返回的是一个int而已。故我们选择int32.。此时我们就可以调用一个方法了吗?像int32 context.getCount();这样。然而当我们直接这样做的时候会发现,并没有对应的方法。那是因为我们只是模型设计器修改了 。相关的映射配置文件并没有修改cs代码。故我们重新生成我们的工程。

此时我们可以看到我们要的方法了但是返回值并不是我们选择的Int32. 我们回过头发现原来他返回的就是一个集合。我们可以这样测试获取所需数据。

  public int getCount()

  {

      SalaryDbContext context = new SalaryDbContext();

      ObjectResult<int?> or = context.getCount();

      int? count = or.First();//我们可以确定他只会返回一个整数,所以取第一个即可。

      context.Dispose();

      return (int)count;

  }

2)例子2;清空三张表数据。我们只需要在选择返回值时选择无即可。

create proc cleartables

as

begin

begin transaction

delete from teacherfeature;

delete from teacherinfo;

delete from feature;

commit transaction

if(@@ERROR<>0)

rollback transaction;

end

3)例子3:根据性格特征id查出特征值最大的老师姓名和特征值。

create proc getMaxdegreeTf(@featureid char(2))

as

begin

select t.teachername,tf1.degree from teacherfeature tf1

join teacherinfo t on tf1.tno=t.tno

where  tf1.degree=

(select MAX(degree) from teacherfeature tf2 where feature_id=@featureid);

end;

在本例子中我们的映射参数为featureid。然而返回值是两个值:teachername,和degree。并不属于以上的标量或者实体。这里会被识别为复杂类型。

  public virtual ObjectResult<TeachernameWithDegree> getMaxdegreeTf(string featureid)

 {

  var featureidParameter = featureid != null ?

      new ObjectParameter("featureid", featureid) :

      new ObjectParameter("featureid"typeof(string));

       return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<TeachernameWithDegree>("getMaxdegreeTf", featureidParameter);

  }

如第一个例子所述。默认情况下复杂类型的名字为方法名。我们将复杂类型修改一下:TeachernameWithDegree。该方法则返回了这个复杂类型的集合。

测试代码:

  //存储过程调用示例

  public List<TeachernameWithDegree> getMaxDegreeTF(String featureid)

 {

   SalaryDbContext context = new SalaryDbContext();

   ObjectResult<TeachernameWithDegree> or = context.getMaxdegreeTf(featureid);

 List<TeachernameWithDegree> list = or.ToList();

     context.Dispose();

      return list;

}

 

2.Ef使用sql

 

  //使用ddl/dml sql

  public void execInsertSql(Feature feature)

  {

    SalaryDbContext context = new SalaryDbContext();

    string sql = @"insert into feature values({0},{1})";

    context.Database.ExecuteSqlCommand(sql,feature.feature_id,feature.feature_name);            

  }

 

 //使用ddl/dml sql

  public List<Teacherinfo> execSelectSql(string id)

  {

  SalaryDbContext context = new SalaryDbContext();

  string sql = @"select * from teacherinfo where tno={0}";       

   string[] paras = {id };

 List<Teacherinfo> teachers=  context.Database.SqlQuery<Teacherinfo>(sql, paras).ToList();

 context.Dispose();

 return teachers;

        }

2.Ef之事务支持

EF的事务需要如上的dll,我们先引入。

 //事务

public void doTrasaction()

{

Feature feature = new Feature();

feature.feature_id = "12";

feature.feature_name = "无趣";//此时这个feature是可以正常插入的

 AddFeature(feature);

 feature = new Feature();

 feature.feature_id = "01";//然而在这里 由于主键约束,这是插不进去的

 feature.feature_name = "可笑";

 AddFeature(feature);

 

}

 

  public void AddFeature(Feature feature)

 {

     SalaryDbContext context = new SalaryDbContext();

     context.features.Add(feature);

     context.SaveChanges();

     context.Dispose();

 

 }

EF本身每一个上下文都已经具备一个隐藏内置事务对象,即同一个上下文下,如果出现错误,是可以自动回滚的。然而事务一般出现在业务逻辑层,而上下文出现在数据访问层。即,同一个业务处理模块,可能出现不同的上下文对象。因为我们的每个数据访问操作都会new一个上下文对象,在执行完毕会被释放。因此,各个数据访问操作相对独立。此时,我们在执行doTrasaction()方法时,将会第一条插入成功。而第二条插入失败,显然不符合事务的要求。

.net为我们提供了这样一种方式

 public void doTrasaction()

  {

 using(TransactionScope scope = new TransactionScope())

       {

  Feature feature = new Feature();

  feature.feature_id = "12";

    feature.feature_name = "无趣";//此时这个feature是可以正常插入的

  AddFeature(feature);

  feature = new Feature();

  feature.feature_id = "01";//然而在这里 由于主键约束,这是插不进去的

  feature.feature_name = "可笑";

  AddFeature(feature);

         }

   }

如上所做,将要执行的事务块放入 using(TransactionScope scope = new TransactionScope())

       {

         //事务代码块

         }

此时就已经具备了事务的能力。简单,方便。TransactionScope 在之前我们导入的System.Trasactions命名空间下。

小贴士:

Sqlserver 存储过程事务的支持

Create PROCEDURE demo
As 

Begin 
Begin Transaction 
Insert Into Lock(LockTypeID) Values('A')--
此语句将出错,LockTypeIDInt类型 ;
Update Lock Set LockTypeID = 1 Where LockID =32 ;

Commit Transaction 
If(@@ERROR <> 0) 

Rollback Transaction 
End 

GO 

上面一个存储过程中黄色的部分为事务的支持方式。

至此我们的入门教程结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值