zoukankan      html  css  js  c++  java
  • 深入解读 Entity Framework 4.0和4.1

      记得去年初就开始关注Entity Framework,那时只是简单测试了一下,发现较之Nhibernate不太成熟。当时的EF主要表驱动方式开发,过度依赖edm文件,并且数据层耦 合了模型层,让一些MVC分层用户痛苦不堪。微软从Oxite1项目发展到Oxite2也在这个DAL与MODEL的理不清的关系上做过徘徊,只好在 EDM的基础上直接实现BLL。由于EntityObject模型与ObjectContext耦合,在N层架构构中EntityObject直接提供给 客户端使用的话,那ObjectContext在客户端也会被调用,因此这个时候只能通过DTO对象的方式解决,而毕竟大部分EntityObject是 可以直接传递使用的,而不是一定通过DTO传递。

      我们看看现在的EF4.0和EF4.1有哪些进步,先来解释一些名词

      EDM文件

      EDM是实体数据关系映射的XML文件,不同于Nhibernate每个对象单独映射了一个XML文件。EDM主要有三部分构成 CSDL,SSDL,MSL。CSDL表面的是实体数据模型结构,SSDL表示对应的数据存储的架构,CSDL实体与SSDL数据结构的关系通过MSL映 射实现。EDM是通过ADO.NET 实体数据模型生成的

    深入解读 Entity Framework 4.0和4.1

      生成EDM文件的方式有两种,一种基于是数据库,一种是创建空EDM模型。前者就是后面要提到的DataBase First方式,后者是Model First方式。

      针对创建好的EDM模型最终要生成代码,生成代码的工具不同,生成的代码也不同。看看下面几种生成方式,都于基于EDM模型生成的。

      ADO.NET 实体数据模型

      最初EF的方式,实体模型EntityObject与ObjectContext耦合在一起,不适合分层使用。

      ADO.NET 自跟踪实体生成器

      分离生成基于POCO的SelfTrackingEnityObject模型和ObjectContext (这种方试即使设置了延迟加载也无法加载关联导航属性,要在使用时手动加载)

      ADO.NET DbContext Generator

      分离生成纯POCO模型和轻型DbContext。DbContext较之ObjectContext比较简洁,并且POCO可以充分利用。

      这就是我为什么选ADO.NET DbContext Generator 的原因,我们再看看EF框架的划分的模式:

      DataBase FirstModel FirstCode First

      DataBase First

      传统的表驱动方式创建edm,然后通过edm生成模型和数据层代码。除生成实体模型和自跟踪实现模型,还支持生成纯POCO模型和轻型DbContext。

      Model First

      先创建EDM模型,再生成DDL数据库脚本和模型和数据层代码。除生成实体模型和自跟踪实现模型,支持生成纯POCO模型和轻型DbContext。

      Code First

      手动创建POCO模型,数据层DbContext及映射关系,通过Database.SetInitializer生成数据库,这种方式较灵活,但是代码工作较多。

      虽然Code First灵活,但是我们不可能手工去写大量的POCO类和映射关系。如果借助其它ORM工具生成Code First的需要POCO类,为什么试试Model First生成Code First需要的代码呢?

      本篇选择基于Model First方式+通过ADO.NET DbContext Generator生成基于Code First方式代码

      ,是不是有点概念混乱?但是这种方式基本上和Nhibernate是一致的,而Nhibernate又有着广泛的项目基础。

      Model First方式

      主要解决构建模型和EDM映射文件工作。

      ADO.NET DbContext Generator

      基于EDM文件生成POCO模型,DbContext代码以及DDL数据库脚本。因为Code First你要自己实现POCO,DbContext的代码,这部分工作如果不借助工具实现代码量还是很大的。做项目不可能像写个Demo用简单的几个类 演示一下就完了,总不能为了演示而学习,最终还是要提高工作效率。这也是为什么我觉得EF已经成熟了决定用于项目的原因。

      下面就把这个过程简单的走一遍:

      1.首先创建项目,类库EF.Model,EF.DAL,EF.BLL,控制台EF.Demo。

      在类库EF.DAL中创建空EDM模型 (为什么要在EF.DAL创建EDM,而不是EF.Model中创建,后面会说明),打开空的EDM模型,我们构建几个实体对象,并映射各个实体间的关系。

      EDM视图如下:

    深入解读 Entity Framework 4.0和4.1
      右键属性选择根据模型生成数据库-> 生成DemoDB.edmx.sql脚本->打开脚本 右键执行SQL 生成到数据库

      2.添加代码生成

      完成我们的对象设计后,右键EMD属性->添加代码生成项...->选择ADO.NET DbContext Generator生成器 ,这个时候EDMX就变成空模板了,属性生成代码策略被关闭

      完成后,会自动生成两个tt文件,一个DemoDB.Context.tt (DbContext),一个DemoDB.tt (POCO)

    深入解读 Entity Framework 4.0和4.1
    深入解读 Entity Framework 4.0和4.1

       我们将DemoDB.edmx和Demo.tt 两个文件COPY到EF.Model中,并且删除掉EF.DAL中的这两个文件。由于DemoDB.edmx和Demo.tt 两个文件是在EF.DAL创建的,所以移到EF.Model中他们的命名空间还是EF.DAL。不用担心,我们在EF.Model中打开 DemoDB.edmx和Demo.tt两个模板文件,点击保存后,模板会自动修改命名空间为EF.Model。注意了EF.DAL中的 DemoDB.Context.tt模板不要打开保存,否则DbContext的代码会丢失。 这样我们完成了Model和DAL代码的分离工作了。

      (DbContext 是EF4.1内容, 另外在VS解决方案的工具里有扩展管理器可直接下载最新的VS扩展插件,通过Library Package Manager的控制台直接添加引用)

      如果对象修改了,我们只要再保存EDM模板就可以及时更新DemoDB.tt中的对象。而DAL层基本上不需要修改。

      3. EF.DAL创建通用数据操作类库(仿Nhibernate)

      IRepository接口:(IOC注入)

      

      using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace EF.DAL{

      public interface IRepositoryT> where T : class, new()

      T Create();

      T Update(T entity); T Insert(T entity);

      void Delete(T entity);

      T Find(params object[] keyValues);

      ListT> FindAll();


      RepositoryBase 抽象基类实现

      

      using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data;using System.Data.Entity;using EF.DAL;namespace EF.DAL{

      public abstract class RepositoryBaseT>:IRepositoryT> where T :class,new()

      public DbContext context; //提供IOC注入方式接口

      public RepositoryBase(DemoDBEntities context)

      { this.context = context;

      } //测试用

      public RepositoryBase() { this.context = new DemoDBEntities();

      } #region IRepositoryT> 成员

      public T Create()

      return context.SetT>().Create();

      public T Update(T entity)

      //执行验证业务

      //context.Entry(entity).GetValidationResult(); if (context.Entry(entity).State == EntityState.Modified) context.SaveChanges();

      return entity;

      public T Insert(T entity)

      context.SetT>().Add(entity);

      context.SaveChanges(); return entity;

      public void Delete(T entity)

      context.SetT>().Remove(entity);

      context.SaveChanges();

      public T Find(params object[]keyValues)

      return context.SetT>().Find(keyValues);

      } public ListT> FindAll()

      return context.SetT>().ToList();

      #endregion

      }}


      IBlogCategoryRepository 接口(IOC注入)

      

      using System;using System.Collections.Generic;using System.Linq;using System.Text;using EF.Model;namespace EF.DAL{

      public interface IBlogCategoryRepository:IRepositoryBlogCategory>


      BlogArticleRepository实现

      

      using System;using System.Collections.Generic;using System.Linq;using System.Text;using EF.Model;namespace EF.DAL{

      public class BlogArticleRepository:RepositoryBaseBlogArticle>,IBlogArticleRepository


      看看后面两个具体数据操作类的代码极其简单,这就是EF4.0 之后的泛型的优点 ,可以使代码尽量的简洁。

      4.EF.BLL层简单的实现一下业务

      BlogCategoryService 实现关联表操作(添加一个BlogCategory分类,并且在这个分类下增加一个BlogArticle文章)

      

      using System;using System.Collections.Generic;using System.Linq;using System.Text;using EF.DAL;using EF.Model;namespace EF.BLL{

      public class BlogCategoryService {

      IRepositoryBlogCategory> repositoryCategory;

      IRepositoryBlogArticle>

      repositoryArticle;

      public BlogCategoryService(IRepositoryBlogCategory>repositoryCategory,IRepositoryBlogArticle> repositoryArticle)

      { this.repositoryCategory = repositoryCategory;

      this.repositoryArticle = repositoryArticle;

      public BlogCategoryService() {

      this.repositoryCategory = new BlogCategoryRepository();

      this.repositoryArticle = new BlogArticleRepository();

      } public BlogCategory CreateBlogCategory()

      return repositoryCategory.Create();

      } public BlogArticle CreateBlogArticle()

      return repositoryArticle.Create();

      public BlogCategory Insert(BlogCategory entity)

      return repositoryCategory.Insert(entity);

      public BlogCategory Update(BlogCategory entity)

      return repositoryCategory.Update(entity);

      public void Delete(BlogCategory entity) { repositoryCategory.Delete(entity);


      5.EF.Model测试导航属性关联操作(同时往两张表插入记录)

      

      using System;using System.Collections.Generic;using System.Linq;using System.Text;using EF.Model;using EF.BLL;namespace EF.Demo{ class Program {

      static void Main(string[] args) {

      BlogCategoryService service=new BlogCategoryService();

      //创建博文分类

      BlogCategory cate = service.CreateBlogCategory();

      cate.CateName = EF分类标签;

      //创建一篇博文

      BlogArticle arti = service.CreateBlogArticle(); arti.Title = EF进化论; arti.Content = EF测试内容; //博文加到博文分类

      cate.BlogArticle.Add(arti);

      //更新 service.Insert(cate);

      Console.ReadLine(); } }}


      6.结果
    深入解读 Entity Framework 4.0和4.1

       通过Model First的方式+ADO.NET DbContext Generator生成器 实现Code First方式业务(EDMX通过DbContext构造注入其中),到达Hibernate的效果。EDMX相当于Hibernate 对象模型XML映射文件,POCO相当于Hibernate对象模型(virtual实现关联导航加载),DbContext通过泛型构建 IRepository数据操作类。之前看到相关测试,微软的EF ADO.NET 测试效率高出Hibernate 30%左右,不知道是不是真的-_-|||。

      另外提一点 DbContext 可以转换为ObjectContext,用Refletor反编译看到是通过一个中间InternalContext实现的

      实现代码: ObjectContext context = ((IObjectContextAdapter) DbContext).ObjectContext;

      如果不想直接加载导航属性数据,你可以在DbContext的构造函数禁用延迟加载。

      

      //// //

      此代码是根据模板生成的。////

      手动更改此文件可能会导致应用程序中发生异常行为。//

      如果重新生成代码,则将覆盖对此文件的手动更改。//

      //

      namespace EF.DAL{

      using System;

      using System.Data.Entity;

      using System.Data.Entity.Infrastructure;

      using EF.Model;

      public partial class DemoDBEntities : DbContext

      public DemoDBEntities() : base(name=DemoDBEntities) {

      //禁用延迟加载 this.Configuration.LazyLoadingEnabled = false;

      //禁用代理 this.Configuration.ProxyCreationEnabled = false;

      protected override void OnModelCreating(DbModelBuilder modelBuilder)

      throw new UnintentionalCodeFirstException();

      public DbSetBlogArticle> BlogArticle { get; set; }

      public DbSetBlogCategoryRepository> BlogCategory { get; set; }

      public DbSetBlogComment> BlogComment { get; set; }

      public DbSetBlogDigg> BlogDigg { get; set; }

      public DbSetBlogMaster> BlogMaster { get; set; }

      public DbSetBlogTag> BlogTag { get; set; }


      EF提供了强大的查询框架,有时间再写篇探讨自定义查询的,至此,不必犹豫不决了,可以在项目中实践一下。

      如果表设计DateTime字段不允许为空,EF执行SaveChanges会出错,建议使用DateTime2类型解决(SQL2008以后版本)

  • 相关阅读:
    Codeforces Beta Round #92 (Div. 2 Only) B. Permutations 模拟
    POJ 3281 Dining 最大流 Dinic算法
    POJ 2441 Arrange the BUlls 状压DP
    URAL 1152 Faise Mirrors 状压DP 简单题
    URAL 1039 Anniversary Party 树形DP 水题
    URAL 1018 Binary Apple Tree 树形DP 好题 经典
    pytorch中的forward前向传播机制
    .data()与.detach()的区别
    Argparse模块
    pytorch代码调试工具
  • 原文地址:https://www.cnblogs.com/end/p/2144250.html
Copyright © 2011-2022 走看看