随笔-197  评论-2252  文章-1  trackbacks-63

终于尝试了一次EF

    其实我对微软出的Linq to Sql,以及Linq to Entity这两个产品兴趣都不大,不太喜欢那种开发模式,主要原因如下:
    1:自动生成的那堆代码,不利于平时的分层模式,将实体以及存储逻辑混合在一起总觉的不是那么回事;
    2:对于编写测试用例不是那么友好,全部逻辑都在一起,无法拆分测试,比如只想测试代码逻辑,不需要连接真正的数据库等。
    3:在排除程序BUG时,还是习惯于看直观的SQL,这样在数据库中调试起来更加容易些,可能是个人习惯问题;
    4:据说性能上存在一定缺陷,本人并未测试过,道听途说而已。

    之所以这次想尝试一次,主要基于两点:首先我现在接手的一个项目是用EF编写的,其次就是EF 4.2能够将原来混合在一起的代码给分离开,说的官方点,这个分离功能叫POCO,英文全名是Plain Old CLR Object,翻译成中文是简单传统的CLR对象。总之最新的EF允许开发人员手工编写更多代码,不再一味的依赖代码自动生成。

    第一:如何安装EF 4.2?

    我电脑上原来安装的是EF 4.0,这次选择的是通过NuGet方式安装。
    1:首先从VS菜单上选择工具,然后选择扩展管理,如下图。
      
   

      2:在弹出框的左侧选择Online,然后在右上角搜索Nuget,最后进行安装。

,
      

    3:安装NUGET后,我们在工程的引用中点击右键,就会多出一项来,如下所示。

        

 

    4:添加EF引用。点击上图中的最后一项,搜索EntityFramework,就会看到最新的EF了,选择进行添加即可。

        

    第二:创建EF程序。
 
    我采用的是最早的模式,即先有数据库,然后再有程序的模式,程序分了如下几层:

 

       

    1:ModelFirstSample.DAL,这是数据层,用于存放与数据库打交道的逻辑;
      先按正常流程添加一个ADO.NET Entity Data Model,按步就班,一步一步下来就行。这样会生成一个.edmx的文件。

 

      

 

     然后打开edmx文件,点击右键选择添加代码生成项,在弹出的菜单中选择Db context那项,接下来会生成PersonModel.tt,PersonModel.Context.tt两文件,对应的edmx下面的自动生成的代码已经为空了。    

 

      

 

    2:ModelFirstSample.Model,实体层,将EF生成的.edmx,.tt文件放在这,与存储逻辑分离;
      将第一步生成的PersonModel.edmx,PersonModel.tt添加到工程下面,同时删除原文件,这样就实现了实体层与存储逻辑的分离。
    3:ModelFirstSample.BLL,业务逻辑层,不用多说;
    4:ModelFirstSample.Service,服务层,对于业务逻辑层的进一步包装;
    5:ModelFirstSample.ConsoleApp,UI层。

    第三:EF中的开发模式之Repository。

    在实际项目中,如果希望能够对存储逻辑有一定的控制,于是就有了repository模式的出现,也就是对原始存储逻辑的一种封装。
    1:在接口层中创建一个通用的存储接口IRepository<T>,便于逻辑复用。

public interface IRepository<T> where T : classnew()
    {
        T Create();
        T Update(T entity);
        T Insert(T entity);
        void Delete(T entity);
        T Find(params object[] keyValues);
        List<T> FindAll();
    }


    2:在DAL层中创建一个实现了IRepository<T>接口的RepositoryBase<T>基类,主要的就是需要提供一个DbContext,基本思想就是利用DbContext的Set<T>构造的类型来提供封装,这里就不做多的说明了,我这里为了简单,使用了默认构造方法,FacePerfEntities是添加edmx时生成的类。
   

View Code
public class RepositoryBase<T> : IRepository<T> where T : class,new()
    {
        public DbContext context;

        public RepositoryBase(DbContext _context)
        {
            this.context = _context;
        }
        public RepositoryBase()
        {
            this.context = new FacePerfEntities();
        }
        #region IRepository<T> 成员

        public T Create()
        {
            return context.Set<T>().Create();
        }

        public T Update(T entity)
        {
            if (context.Entry<T>(entity).State == EntityState.Modified)
                context.SaveChanges();
            return entity;
        }

        public T Insert(T entity)
        {
            context.Set<T>().Add(entity);
            context.SaveChanges();
            return entity;
        }

        public void Delete(T entity)
        {
            context.Set<T>().Remove(entity);
            context.SaveChanges();
        }

        public T Find(params object[] keyValues)
        {
            return context.Set<T>().Find(keyValues);
        }

        public List<T> FindAll()
        {
            return context.Set<T>().ToList();
        }

        #endregion
    }

 

    3:在接口层中创建一个关于员工的接口:IEmployeeRepository<T>
   

public  interface IEmployeeRepository<T>
    {
       List<T> SearchEmployee();

    }

 

    4:在业务逻辑层中创建关于员工的专用类:EmployeeRepositoryBLL。
   

public class EmployeeRepositoryBLL : IEmployeeRepository<Employee>
    {
        EmployeeRepository repository = new EmployeeRepository();
        public List<Employee> SearchEmployee()
        {
            return repository.FindAll();
        }

    }

 

    5:在服务层中创建员工的服务类,由于这只是测试用,所以服务类起的作用并不明显,至于为什么有服务层,是为了将UI层与业务逻辑层分离等等众多原因。

View Code
public  class EmployeeRepositoryService
    {
       EmployeeRepositoryBLL repositoryEmployee=null  ;
       public EmployeeRepositoryService()
       {
          repositoryEmployee = new EmployeeRepositoryBLL();
       }
       public List<Employee> SearchEmployee()
       {
          return this.repositoryEmployee.SearchEmployee();
          
       }
    }

   

    6:最后就是UI了。
   

View Code
static void Main(string[] args)
        {
            EmployeeRepositoryService ers = new EmployeeRepositoryService();
            var list = ers.SearchEmployee();
            var people = from p in list
                         orderby p.CreatedOn
                         select p;

            Console.WriteLine("All People:");
            foreach (var person in people)
            {
                Console.WriteLine("- {0}", person.ChineseName);
            }
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }


     补充说明:

     1:添加完edmx后,以及完成添加代码生成项后,查询PersonModel.Context.cs,代码如下:
    

public FacePerfEntities()
            : base("name=FacePerfEntities")
        {
        }

 

       构造函数中的参数FacePerfEntities,其实就对应EF数据库连接串的节点名称。

     2:添加完edmx后,在DAL层还会有一个packages.config文件,这个文件不用发布到UI程序下面,也不影响程序运行,只需要将连接串对应的节点复制到UI配置文件中即可。

     总结: 经过上面的改造,已经越来越适合实际项目了,EF在不断改进,我想在一些小型项目中快速开发倒是蛮适合的。

 

注:本文参考

           http://blogs.msdn.com/b/adonet/archive/2011/09/28/ef-4-2-model-amp-database-first-walkthrough.aspx

           http://www.cnblogs.com/mecity/archive/2011/07/07/2099598.html

           http://www.cnblogs.com/chsword/archive/2011/09/14/NuGet_Install_OperatePackage.html

      

posted on 2011-12-13 16:10 min.jiang 阅读(2480) 评论(15) 编辑 收藏

评论:
#1楼 2011-12-13 16:40 | Jake Lin      
我挺喜欢ef,测试可以用moq来setup那些数据操作。
 回复 引用 查看   
#2楼 2011-12-13 17:17 | testzhangsan      
Codeplex 上面很多。
 回复 引用 查看   
#3楼 2011-12-13 17:40 | FlyDragon      
楼主:
按照楼主不喜欢用EF以下四点,我简单谈一下我的经验,如有不足还请见谅,只是谈技术,不针对个人。

1:自动生成的那堆代码,不利于平时的分层模式,将实体以及存储逻辑混合在一起总觉的不是那么回事;

【我的意见:你可以不选择EF自动生成的代码,EF支持POCO,而且最新EF支持Code Only!完全可以我们自己进行驾驭,存储逻辑我们可以放到Repository中,跟EF没关系,还是你的选择的问题。】
2:对于编写测试用例不是那么友好,全部逻辑都在一起,无法拆分测试,比如只想测试代码逻辑,不需要连接真正的数据库等。
【我的意见:没觉得那里不好,完全可以只测试逻辑】

3:在排除程序BUG时,还是习惯于看直观的SQL,这样在数据库中调试起来更加容易些,可能是个人习惯问题;
【可以使用:Sqlprofile来监控生成的sql语句】
4:据说性能上存在一定缺陷,本人并未测试过,道听途说而已。
【性能我觉得没什么问题,只是比简单执行sql多了一层生成sql的过程而已,而对应整个应用的性能消耗的瓶颈一般不在这。】

仅仅个人观点!

 回复 引用 查看   
#4楼[楼主] 2011-12-13 17:54 | min.jiang      
@FlyDragon
都是学习,希望多多讨论,有错误的地方多多指教,
第一点:正是由于EF 4.2支持了POCO,这才决定尝试呀。
第二点:有时测试需要测试假功能,即程序创建些数据结构进行模似测试,并不需要数据库环境,现在有了repository后,就可以实现了。
第三点:EF生成的语句虽然在语义上是一样的,但写法有点别扭,没有程序员自己写的思路明确,往往程序员写的来的简单,比如写一个分页程序,生成的代码会繁锁些。
第四点:性能问题,我也只是道听途说,哈哈,目前还未真正遇到过。

 回复 引用 查看   
#5楼 2011-12-13 18:01 | FlyDragon      
引用min.jiang:
@FlyDragon
都是学习,希望多多讨论,有错误的地方多多指教,
第一点:正是由于EF 4.2支持了POCO,这才决定尝试呀。
第二点:有时测试需要测试假功能,即程序创建些数据结构进行模似测试,并不需要数据库环境,现在有了repository后,就可以实现了。
第三点:EF生成的语句虽然在语义上是一样的,但写法有点别扭,没有程序员自己写的思路明确,往往程序员写的来的简单,比如写一个分页程序,生成的代码会繁锁些。
第四点:性能问题,我也只是道听途说,哈哈,目前还未真正遇到过。

EF生成的Sql是有点可读性差,但是认真看还是生成的sql是优化过的,include生的sql还是比较差的,其他的大部分情况下还是比较好的,至于分页那个还是生成的相当不错的,EF的小组专门请了Sql的专家帮助生成优化的sql语句,所以还是可以看见一些生成的sql比较专业的。

 回复 引用 查看   
#6楼 2011-12-13 19:22 | LoveJenny      
支持下
 回复 引用 查看   
#7楼 2011-12-13 23:54 | Life a Poem      
好文章,支持,EF还是值得期待的
 回复 引用 查看   
#8楼 2011-12-14 08:26 | zesion      
EF.还是用CODE first 比较爽。
 回复 引用 查看   
#9楼 2011-12-14 10:12 | C#通用权限管理系统组件      
很多时候,我们都怕迈出 第一步,只要迈出了第1步,接着都很好说。
 回复 引用 查看   
#10楼 2011-12-15 11:31 | xjb      
你可以把执行的sql打印出来呀
 回复 引用 查看   
#11楼 2011-12-15 13:07 | Tender      
我专门做过测试,ef性能很差,如果个人做项目玩玩,用ef还行,但是中大型项目,几乎不能够用ef。
 回复 引用 查看   
#12楼 2011-12-15 13:14 | CoffeeDeveloper      
@Tender
求测试数据.不能只说空话呀.

 回复 引用 查看   
#13楼 2011-12-15 13:35 | Tender      
引用CoffeeDeveloper:
@Tender
求测试数据.不能只说空话呀.


这个我比较的是nhibernate,EF,ADO.NET 这三种的性能。因为ef4.1不支持批量操作,性能上是很吃亏的。估计以后的版本会支持吧

 回复 引用 查看   
#14楼 2011-12-15 14:20 | 柒寒      
楼主,明显带有偏见,1:自动生成的那堆代码,不利于平时的分层模式,将实体以及存储逻辑混合在一起总觉的不是那么回事;我就在用这个,光看了你这句就发了,之后再看文章。我想说这个EF用起来其实很方便。但是对于某一个对象操作的话,就是不可以改变他的值这个让我很苦恼。
 回复 引用 查看   
#15楼 2012-01-13 22:37 | 我想我是青蛙      
@Tender
个人觉得互联网小型项目,还有就是企业内部开发,用EF绝对是首选。别的应用就应该掂量了。

 回复 引用 查看   
min的个人网站终于创建起来了
昵称:min.jiang
园龄:5年6个月
粉丝:144
关注:8
<2011年12月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

常用链接

最新随笔

随笔分类

随笔档案

Follow Me

博客园友情链接

拳皇比赛视频

积分与排名

  • 积分 - 493980
  • 排名 - 124

最新评论

阅读排行榜

评论排行榜

推荐排行榜