一步一步学EF系列【5、升级篇 实体与数据库的映射】live writer真坑,第4次补发
前言
之前的几篇文章,被推荐到首页后,又被博客园下了,原因内容太少,那我要写多点呢,还是就按照这种频率进行写呢?本身我的意图这个系列就是想已最简单最容易理解的方式进行,每篇内容也不要太多,这样初学者容易理解学习,否则天花乱坠的一大篇初学者从头看到尾也要晕了。所以每次突出重点进行浓缩精华时的讲,当然我这样精简讲,你们要学深入的话,也还是要把有些概念学深入一下。也欢迎大家共同讨论学习。我这里创建了一个QQ群(435498053),大家也可以加群交流。
正文
本篇还是作为之前的升级篇,其实前面2-3篇可以合并,但我觉得直接合并不能让人很容易理解,先来一篇最基础的,然后在循序渐进的进行深入和代码方面的封装简化。我们不废话了,接着上篇讲,上篇最后的时候大家还记得最终写好的代码吗?我把代码贴出来一块回顾一下。
//实体集合
public IDbSet<BlogUser> BlogUsers { get; set; }
public IDbSet<Post> Posts { get; set; } /// <summary>
/// 重写配置类
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new BlogUserConfiguration());
modelBuilder.Configurations.Add(new PostConfiguration());
}
上一篇我们提出这样写是为了简化在OnModelCreating中把每个表的配置写到这里,但是用心的朋友应该看到,你这样写其实也还是很麻烦啊!按照现在的写法难道我每次建一个实体都要在这里创建一个实体集合,然后在下面在加入一个modelBuilder.Configurations.Add(new XXXConfiguration());所以问题还是一样的存在。具体看下面
由代码可以看出,当前的上下文类与业务实体是强耦合的,分别耦合在DbSet<TEntity>的属性与OnModelCreating方法上。那解决办法呢?当然要解耦。对于属性,可以使用DbContext.Set<TEntity>()方法来实现指定实体的属性,对于OnModelCreating中的方法实现中的映射配置对象,则可提取一个通用接口,通过接口进行分别映射。那我们就分两步来讲解如何解耦!
一、提取一个IEntityMapper通用接口,通过接口进行分别映射。
1、定义接口的代码如下:
/// <summary>
/// 实体映射接口
/// </summary>
public interface IEntityMapper
{
///<summary>
/// 将当前实体映射对象注册到当前数据访问上下文实体映射配置注册器中
/// </summary>
/// <param name="configurations">实体映射配置注册器</param>
void RegistTo(ConfigurationRegistrar configurations);
}
2、在实体映射类中添加IEntityMapper的实现。我们已BlogUser作为实例演示。代码如下
/// <summary>
/// 博客用户信息映射类
/// </summary>
public class BlogUserConfiguration : EntityTypeConfiguration<BlogUser>,IEntityMapper
{
public BlogUserConfiguration()
{
//设置主键
HasKey(m => m.BlogUserId);
} public void RegistTo(System.Data.Entity.ModelConfiguration.Configuration.ConfigurationRegistrar configurations)
{
configurations.Add(this);
//throw new NotImplementedException();
}
}
3、这样定义好了,那是不是要考虑的是怎么能在OnModelCreating自动调用实现IEntityMapper进行自动注册呢!这里办法有很多,有知道IOC的朋友应该会想到用依赖注入的方式就可以,引入所有实现了IEntityMapper的类的对象。但是我这里先不用IOC组件干这个事情,我们还是先按照最传统的方式来进行。
我们具体要怎么做的思路都有了吧?就是引入所有实现了IEntityMapper的类的对象,然后遍历,调用其中的RegistTo进行实体映射类对象的添加。
第一步,获取所有实现了IEntityMapper的类的对象,看代码
private static ICollection<IEntityMapper> GetAllEntityMapper()
{
ICollection<Assembly> EntityMapperAssemblies = EntityMapperAssemblies = new[]
{
Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.RelativeSearchPath, "EFCore.dll"))
};
if (EntityMapperAssemblies.Count == )
{
throw new InvalidOperationException("上下文“{0}”初始化失败,请添加实体映射程序集");
}
Type baseType = typeof(IEntityMapper);
Type[] mapperTypes = EntityMapperAssemblies.SelectMany(assembly => assembly.GetTypes())
.Where(type => baseType.IsAssignableFrom(type) && type != baseType && !type.IsAbstract).ToArray();
ICollection<IEntityMapper> result = mapperTypes.Select(type => Activator.CreateInstance(type) as IEntityMapper).ToList();
return result;
}上面的这段我是参考过别人的代码的,具体哪个博客我不记得了,到时候找到我在添加上引用。原理也比较简单就是我加载我写实体类的EFCore.dll的程序集,这个dll名称要按你实际项目的dll名称为主,这个名字现在是我自己的demo。然后把实现IEntityMapper的类找到,然后通过CreateInstance创建该类型的实例,原理就这个。
第二步,遍历对象,调用其中的RegistTo进行实体映射类对象的添加
/// <summary>
/// 重写配置类
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// base.OnModelCreating(modelBuilder);
//modelBuilder.Configurations.Add(new BlogUserConfiguration());
//modelBuilder.Configurations.Add(new PostConfiguration()); modelBuilder.Entity<BlogUser>().HasKey(m => m.BlogUserId); IEnumerable<IEntityMapper> EntityMappers = GetAllEntityMapper();
if (EntityMappers == null)
{
return;
}
foreach (var mapper in EntityMappers)
{
mapper.RegistTo(modelBuilder.Configurations);
} }然后就完成了,运行你的代码。是不是也成功了。
我把完整的代码在附上
/// <summary>
/// 重写配置类
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// base.OnModelCreating(modelBuilder);
//modelBuilder.Configurations.Add(new BlogUserConfiguration());
//modelBuilder.Configurations.Add(new PostConfiguration()); modelBuilder.Entity<BlogUser>().HasKey(m => m.BlogUserId); IEnumerable<IEntityMapper> EntityMappers = GetAllEntityMapper();
if (EntityMappers == null)
{
return;
}
foreach (var mapper in EntityMappers)
{
mapper.RegistTo(modelBuilder.Configurations);
} } private static ICollection<IEntityMapper> GetAllEntityMapper()
{
ICollection<Assembly> EntityMapperAssemblies = EntityMapperAssemblies = new[]
{
Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.RelativeSearchPath, "EFCore.dll"))
};
if (EntityMapperAssemblies.Count == )
{
throw new InvalidOperationException("上下文“{0}”初始化失败,请添加实体映射程序集");
}
Type baseType = typeof(IEntityMapper);
Type[] mapperTypes = EntityMapperAssemblies.SelectMany(assembly => assembly.GetTypes())
.Where(type => baseType.IsAssignableFrom(type) && type != baseType && !type.IsAbstract).ToArray();
ICollection<IEntityMapper> result = mapperTypes.Select(type => Activator.CreateInstance(type) as IEntityMapper).ToList();
return result;
}我这里作为演示也不要新建类进行封装,写的一起主要看起来方便而已。
二、对于属性,可以使用DbContext.Set<TEntity>()方法来实现指定实体的属性
上面我们通过提前了一个IEntityMapper接口实现了OnModelCreating里面的代码的解耦。那这里我们就要想办法处理如下的代码。
public IDbSet<BlogUser> BlogUsers { get; set; }
public IDbSet<Post> Posts { get; set; }
……上面也提到了解决办法就是通过DbContext.Set<TEntity>()方法来实现指定实体的属性,具体怎么操作呢?其实这个要比处理配置类简单多了,当然也还是直接看代码。
public ActionResult Index()
{ var db= new BlogDbContext(); return View(db.Posts.ToList()); }这个代码是第一篇里面的,获取Posts里面的数据,然后返回的前台展示。还记得吗?不记得翻到第一篇看看。
上面的代码大家都见过第一篇里面的,那如果解耦的话这里用db.Posts是不是就不存在了,那要怎么做呢!同样看代码
public ActionResult Index()
{
var dbContext = new BlogDbContext();
IQueryable<Post> Posts = dbContext.Set<Post>
();
return View(Posts.ToList());
}这个就是上面说的用DbContext.Set<TEntity>()方法来实现指定实体的属性。简单吗?一句话就可以搞定。
最后我把我们最终的源码发布一下
public BlogDbContext()
: base()
{ }
///实体集合
// public IDbSet<BlogUser> BlogUsers { get; set; }
//public IDbSet<Post> Posts { get; set; } /// <summary>
/// 重写配置类
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// base.OnModelCreating(modelBuilder);
//modelBuilder.Configurations.Add(new BlogUserConfiguration());
//modelBuilder.Configurations.Add(new PostConfiguration()); modelBuilder.Entity<BlogUser>().HasKey(m => m.BlogUserId); IEnumerable<IEntityMapper> EntityMappers = GetAllEntityMapper();
if (EntityMappers == null)
{
return;
}
foreach (var mapper in EntityMappers)
{
mapper.RegistTo(modelBuilder.Configurations);
} } private static ICollection<IEntityMapper> GetAllEntityMapper()
{
ICollection<Assembly> EntityMapperAssemblies = EntityMapperAssemblies = new[]
{
Assembly.LoadFrom(Path.Combine(AppDomain.CurrentDomain.RelativeSearchPath, "EFCore.dll"))
};
if (EntityMapperAssemblies.Count == )
{
throw new InvalidOperationException("上下文“{0}”初始化失败,请添加实体映射程序集");
}
Type baseType = typeof(IEntityMapper);
Type[] mapperTypes = EntityMapperAssemblies.SelectMany(assembly => assembly.GetTypes())
.Where(type => baseType.IsAssignableFrom(type) && type != baseType && !type.IsAbstract).ToArray();
ICollection<IEntityMapper> result = mapperTypes.Select(type => Activator.CreateInstance(type) as IEntityMapper).ToList();
return result;
}
现在如果你在新加一个实体类,就可以不用改这里呆任何一句代码了。已经完全解耦了。是不是蛮简单。
结语
这篇完了以后,其实最基础版的EF学习算是完了。之前的这几篇也希望初学者都能掌握。后面的话要深入的讲解一下,到时候会讲到IOC ,还有Repository,UnitOfWork,DbContext。这些也都是我们在正式项目使用中要用到的。
欢迎大家交流。多些支持。QQ群(435498053) 
一步一步学EF系列【5、升级篇 实体与数据库的映射】live writer真坑,第4次补发的更多相关文章
- 一步一步学EF系列【4、升级篇 实体与数据库的映射】live writer真坑,第4次补发
前言 之前的几篇文章,被推荐到首页后,又被博客园下了,原因内容太少,那我要写多点呢,还是就按照这种频率进行写呢?本身我的意图这个系列就是想已最简单最容易理解的方式进行,每篇内容也不要太多,这样初学者容 ...
- 一步一步学EF系列3【升级篇 实体与数据库的映射】
之前的三张为基础篇,如果不考虑架构问题,做一般的小程序,以足够用了.基本的增删改查也都有了.但是作为学习显然是不够的.通过之前三章的学习,有没有发现这样写有什么问题,有没有觉得繁琐的?可能有人会说,之 ...
- 一步一步学EF系列四【升级篇 实体与数据库的映射】
之前的三张为基础篇,如果不考虑架构问题,做一般的小程序,以足够用了.基本的增删改查也都有了.但是作为学习显然是不够的.通过之前三章的学习,有没有发现这样写有什么问题,有没有觉得繁琐的?可能有人会说,之 ...
- 一步一步学EF系列【6、IOC 之AutoFac】
前言 之前的前5篇作为EF方面的基础篇,后面我们将使用MVC+EF 并且使用IOC ,Repository,UnitOfWork,DbContext来整体来学习.因为后面要用到IOC,所以本篇先单独先 ...
- 一步一步学EF系列 【7、结合IOC ,Repository,UnitOfWork来完成框架的搭建】
前言 距离上一篇已经有段时间了,最近这段时间赶上新项目开发,一直没有时间来写.之前的几篇文章,主要把EF的基础都讲了一遍,这批文章就来个实战篇. 个人在学习过程中参考博客: Entity Framew ...
- 一步一步学EF系列一【最简单的一个实例】
整个文章我都会用最简单,最容易让人理解的方式给大家分享和共同学习.(由于live Writer不靠谱 又得补发一篇) 一.安装 Install-Package EntityFramework 二.简单 ...
- 一步一步学EF系列2【最简单的一个实例】
整个文章我都会用最简单,最容易让人理解的方式给大家分享和共同学习.(由于live Writer不靠谱 又得补发一篇) 一.安装 Install-Package EntityFramework 二.简单 ...
- 一步一步学EF系列三【数据迁移】
我们每篇的内容都不多,所以希望在学习的过程中最后能亲自敲一下代码 这样更有利于掌握. 我们现在接着上篇的例子,我们现在给随便的表增加一个字段 CreateTime 创建日期 运行一下 看看会怎么样 修 ...
- 一步一步学EF系列1【Fluent API的方式来处理实体与数据表之间的映射关系】
EF里面的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面,还有一个就是F ...
随机推荐
- ChemDraw Pro绘制无环链结构的两种方法
ChemDraw Pro 14是一款专门针对化学图形绘制而开发制作的编辑软件,是目前工科类常用的绘制化学结构工具,用于快速绘制常用的环结构组成.以下教程讲解ChemDraw Pro绘制无环链结构的两种 ...
- 九度OJ 上剑指 offer 习题目录
<剑指Offer>面试题集收录汇总 面试题1 赋值运算符函数 不适合在线模式 面试题2 实现Singleton模式 不适合在线模式 面试题3 二维数组中的查找 已收录 面试题4 替换空格 ...
- 判断uiscrollView滑到底部
本文转载至 http://blog.csdn.net/cerastes/article/details/39612177 -(void)scrollViewDidScroll:(UIScrollVi ...
- 84、PullToRefresh使用详解
PullToRefresh使用详解(一)--构建下拉刷新的listView http://blog.csdn.net/harvic880925/article/details/17680305 Pul ...
- 深搜———ZOJ 1004:anagrams by stack
细节问题各种虐!! 其实就是简单的一个深搜 看成二叉树来理解:每个节点有两个枝:入栈和出栈. 剪枝操作:只有当栈顶元素和当前位置的目标字符相同时才出栈,否则就不出栈 dfs写三个参数:depth搜索深 ...
- 一个网络设备的常见功能--连通性检查SSRF漏洞--被黑客利用当做扫描器
一.我们先来看一下很多网络设备都有的一个常见功能--连通性测试: 很多网络设备都具备与其他设备通信,联动的功能,例如网络设备联动安全设备,网络设备联动认证设备等等.此时都需要一个对端IP和对端端口号作 ...
- 【BZOJ2525】[Poi2011]Dynamite 二分+树形DP
[BZOJ2525][Poi2011]Dynamite Description Byteotian Cave的结构是一棵N个节点的树,其中某些点上面已经安置了炸.药,现在需要点燃M个点上的引线引爆所有 ...
- eclipse中的SVN文件还原到历史版本
转载自:http://www.softown.cn/post/103.html 由于某些特殊原因,我们可能需要将SVN资源库中的某个文件回滚到以前的某个历史版本(准确地说,这不是"回滚&qu ...
- LeetCode 笔记系列11 First Missing Positive [为什么我们需要insight]
题目: Given an unsorted integer array, find the first missing positive integer. For example,Given [1,2 ...
- Mac自带Apache和Php
Mac 是默认安装 apache和php,但是需要使用root用户来启用,所以请按照我下面的步骤来: 一.启用root用户1.选取系统偏好设置....2.从显示菜单中,选取“帐户”.3.点按锁图标并使 ...