Entity Framework之犹豫不决

2023-11-22 08:20

本文主要是介绍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框架的划分的模式
  1. DataBase First
  2. Model First
  3. Code 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视图如下
右键属性选择根据模型生成数据库-> 生成DemoDB .edmx.sql脚本->打开脚本 右键执行SQL 生成到数据库
2.添加代码生成
完成我们的对象设计后,右键EMD属性->添加代码生成项...->选择ADO.NET DbContext Generator生成器 ,这个时候EDMX就变成空模板了,属性生成代码策略被关闭
完成后,会自动生成两个tt文件,一个DemoDB.Context.tt (DbContext),一个DemoDB.tt (POCO)
我们将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注入)
View Code
using System;
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之犹豫不决的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/408807

相关文章

Spring Framework系统框架

序号表示的是学习顺序 IoC(控制反转)/DI(依赖注入): ioc:思想上是控制反转,spring提供了一个容器,称为IOC容器,用它来充当IOC思想中的外部。 我的理解就是spring把这些对象集中管理,放在容器中,这个容器就叫Ioc这些对象统称为Bean 用对象的时候不用new,直接外部提供(bean) 当外部的对象有关系的时候,IOC给它俩绑好(DI) DI和IO

安卓aosp14上自由窗口划线边框Freeform Caption实战开发-千里马framework实战

背景: 上一篇文章也分享过aosp14版本上自由窗口的Caption栏的显示原理,今天来讲解一下aosp14版本上如何实现对自由窗口的划线边框功能,相关功能已经在aosp13上面进行实现,具体可以看我的分屏自由窗口专题哈。 就是想要在aosp14上面实现如下功能: 即自由窗口在被触摸放大缩小时候,边框要被画成红色的线条,表示选中。 尝试aosp13老方案: 因为aosp13是在acti

Android Framework中的PolicyManager简介

PolicyManager类位于framework\base\core\java\com\android\internal\policy目录中的PolicyManager.java文件中。PolicyManager主要用于创建Window类、LayoutInflater类和WindowManagerPolicy类,它扮演着简单工厂模式中的工厂类角色,而抽象产品角色由IPolicy接口实现,具体产

知识图谱(knowledge graph)——RDF(Resource Description Framework)

RDF的基本单元是三元组(triple) 每个三元组是(主语 谓语 宾语) 这样的元组tuple。主谓宾的取值称为"资源"(Resource, 也就是RDF里的R) 资源可以是一个网址(URI),一个字符串或数 字(严格来讲都是带类型的字符串,称为 literal),或者一个“空节点”(blank node)。 有两种特殊类型的资源。rdfs:Class代表类。 rdf:Property代

缺少各种framework会报的错误

参考: 1、关于缺少各种framework出现的错误累结

【论文】A Collaborative Transfer Learning Framework for Cross-domain Recommendation

Intro 业界常见的跨域建模方案主要分为两种范式[22][32][5][36][17][14][20]:1) 将源样本和目标样本进行联合和混合,然后执行多任务学习技术,以提高在所有域中的性能;2) 使用混合或数据丰富的源域数据预先训练模型,然后在数据不足的目标域中对其进行微调,以适应新的数据分布。在第一种方法中,通过不同类型的网络设计来学习特定域特征和域不变特征,其中域指标通常用于识别域。在微

xcode 打包framework时去除某些架构

下图所示为编译后的.framework文件: 已知该.framework支持的真机架构为arm64和armv7两种。现在想要缩小framework库的容量,只保留arm64架构。Terminal中运行: lipo MySencodeFrameWork.framework/MySencodeFrameWork -thin arm64 -output MySencodeFrameWork 模拟

详解Framework

[Cocoa]深入浅出 Cocoa 之 Framework 罗朝辉( http://blog.csdn.net/kesalin/) CC许可,转载请注明出处 Framework 简介 Mac OS X 扩展了 framework 的功能,让我们能够利用它来共享代码和资源。framework 在概念上有点像 Window 下的库,但是比库更加强大,通过 framework

Android Framework(三)Activity启动流程

文章目录 大纲总体流程 第一阶段:点击图标启动应用流程概览SourceActivity端处理system_service处理启动请求参数的构建activityInfo的解析创建ActivityRecord 窗口层级树的处理获取Task--getOrCreateRootTaskActivityRecord挂载到Task--setNewTask移动Task到容器顶部--moveToFront 显

android-Framework,imageLoading, Animations,Network,Tast/Job

Framework: Common afinal Afinal是一个android的ioc,orm框架https://github.com/yangfuhai/afinalxUtils** android orm, bitmap, http, view inject...https://github.com/wyouflf/xUtilsThinkAndroid ThinkAndroid是一