犹豫不决"/>
Entity Framework之犹豫不决
Entity Framework之犹豫不决
记得去年初就开始关注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 实体数据模型生成的 生成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 First
- Model First
- Code First
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace EF.DAL
{
public interface IRepository < T > where T : class , new ()
{
T Create();
T Update(T entity);
T Insert(T entity);
void Delete(T entity);
T Find( params object [] keyValues);
List < T > FindAll();
}
} RepositoryBase 抽象基类实现 View Code 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 RepositoryBase < T > :IRepository < T > where T : class , new ()
{
public DbContext context;
// 提供IOC注入方式接口
public RepositoryBase(DemoDBEntities context)
{
this .context = context;
}
// 测试用
public RepositoryBase()
{
this .context = new DemoDBEntities();
}
#region IRepository<T> 成员
public T Create()
{
return context.Set < T > ().Create();
}
public T Update(T entity)
{
// 执行验证业务
// context.Entry<T>(entity).GetValidationResult();
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
}
} IBlogCategoryRepository 接口(IOC注入) View Code using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EF.Model;
namespace EF.DAL
{
public interface IBlogCategoryRepository:IRepository < BlogCategory >
{
}
} BlogArticleRepository实现 View Code using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EF.Model;
namespace EF.DAL
{
public class BlogArticleRepository:RepositoryBase < BlogArticle > ,IBlogArticleRepository
{
}
} 看看后面两个具体数据操作类的代码极其简单,这就是EF4.0 之后的泛型的优点 ,可以使代码尽量的简洁。 4.EF.BLL层简单的实现一下业务 BlogCategoryService 实现关联表操作(添加一个BlogCategory分类,并且在这个分类下增加一个BlogArticle文章) View Code using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EF.DAL;
using EF.Model;
namespace EF.BLL
{
public class BlogCategoryService
{
IRepository < BlogCategory > repositoryCategory;
IRepository < BlogArticle > repositoryArticle;
public BlogCategoryService(IRepository < BlogCategory > repositoryCategory,IRepository < BlogArticle > 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测试导航属性关联操作(同时往两张表插入记录) View Code 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.结果 通过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的构造函数禁用延迟加载。 View Code // ------------------------------------------------------------------------------
// <auto-generated>
// 此代码是根据模板生成的。
//
// 手动更改此文件可能会导致应用程序中发生异常行为。
// 如果重新生成代码,则将覆盖对此文件的手动更改。
// </auto-generated>
// ------------------------------------------------------------------------------
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 DbSet < BlogArticle > BlogArticle { get ; set ; }
public DbSet < BlogCategoryRepository > BlogCategory { get ; set ; }
public DbSet < BlogComment > BlogComment { get ; set ; }
public DbSet < BlogDigg > BlogDigg { get ; set ; }
public DbSet < BlogMaster > BlogMaster { get ; set ; }
public DbSet < BlogTag > BlogTag { get ; set ; }
}
} EF提供了强大的查询框架,有时间再写篇探讨自定义查询的,至此,不必犹豫不决了,可以在项目中实践一下。 如果表设计DateTime字段不允许为空,EF执行SaveChanges会出错,建议使用DateTime2类型解决(SQL2008以后版本) 源码下载
更多推荐
Entity Framework之犹豫不决
发布评论