EF6CodeFirst+MVC5+Autofac泛型注册 入门实例
贴一个EF6 CodeFirst模式结合MVC5和Autofac(泛型注册)的一个入门实例
网上类似的例子实在太少,最近自己也有用到这一块的知识,总结了一下,不要让后人踩了自己踩过的坑。
1:新建三个项目,Web(MVC)、EntityFramework类库(EF框架)、Core类库(核心框架),nuget EntityFramework
2:建立简单对象:书籍(Book)Model,继承主键为Int的基类
①:接口
namespace:Core.Domain.Interface
/// <summary>
/// 实体对象接口
/// </summary>
public interface IEntity<PrimaryKeyType>
{
/// <summary>
/// 主键
/// </summary>
PrimaryKeyType Id { get; }
}
IEntity
②:基类
namespace:Core.Domain.Base
/// <summary>
/// Int抽象基类
/// </summary>
/// <typeparam name="Type"></typeparam>
public abstract class EntityBase : Interface.IEntity<int>
{
#region Properties
/// <summary>
/// 数据状态
/// </summary>
public Enum.EntityEnumType Status { get; set; }
public DateTime CreateDate { get; set; }
public DateTime UpdateDate { get; set; }
/// <summary>
/// 主键
/// </summary>
[Key]
public int Id { get; set; }
#endregion
#region Constructor
public EntityBase() :this(Enum.EntityEnumType.Normal,DateTime.Now,DateTime.Now)
{ }
/// <summary>
/// 带参初始化
/// </summary>
public EntityBase(Enum.EntityEnumType _status,DateTime _createDate,DateTime _updateDate)
{
Status = _status;
CreateDate = _createDate;
UpdateDate = _updateDate;
}
#endregion
#region Methods
#endregion
}
EntityBase
③:书籍类
namespace:Web.Models
[Table("Book")]//表名
/// <summary>
/// 实体—书籍
/// </summary>
public class Book:EntityBase
{
#region Constructor
public Book()
: base()
{ }
#endregion
#region Fileds
/// <summary>
/// 书籍编号
/// </summary>
[DisplayName("书籍编号")]
public int BookCode { get; set; }
/// <summary>
/// 书名
/// </summary>
[DisplayName("书名")]
[MaxLength(,ErrorMessage = ,ErrorMessage = "书名过短")]
public string BookName { get; set; }
/// <summary>
/// 作者
/// </summary>
[MaxLength(,ErrorMessage = "作者姓名过长")]
[DisplayName("作者")]
public string Author { get; set; }
#endregion
#region 导航属性
#endregion
#region IEntity成员
#endregion
}
Book
解释一下类的配置
CodeFirst 利用一种被称为约定(Conventions)优于配置(Configuration)的编程模式允许你使用自己的 对象 来表示 EF 所依赖的模型去执行查询、更改追踪、以及更新功能
简单的说,你创建的对象必须遵循EF给你指定的规则,比如最后两位以Id为结尾就是主键啊什么什么什么,反正我是没遵循。
如果你不想遵循EF的规则,那么——
Code First 提供了两种方式来配置你的类:
- DataAnnotations, 使用简单属性;
- Fluent API, 以编程命令行式的方式来描述你的配置
有关于配置的文章,请参考
EF官方文档:https://msdn.microsoft.com/en-us/library/ee712907(v=vs.113).aspx
另外,有问题记得F1看文档,不要一直百度

3:仓储Repository设计
①:IRepository
namespace:Core.Repository
public interface IRepository<TEntity> where TEntity:class
{
/// <summary>
/// 添加一个对象
/// </summary>
/// <param name="item"></param>
void Insert(TEntity item);
/// <summary>
/// 删除一个对象
/// </summary>
void Delete(TEntity item);
/// <summary>
/// 更新一个对象
/// </summary>
void Update(TEntity item);
/// <summary>
/// 通过主键取对象
/// </summary>
/// <returns></returns>
TEntity Find(params object[] id);
/// <summary>
/// 拿到可查询结果集
/// </summary>
/// <returns></returns>
System.Linq.IQueryable<TEntity> GetModel();
/// <summary>
/// 设置数据上下文
/// </summary>
/// <param name="db"></param>
void SetDataContextByResloveName(string dbContext);
}
IRepository
SetDataContextByResloveName这个方法,到下文的Autofac配置时再说
②:IExtentionRepository 扩展
namespace:Core.IExtentionRepository
/// <summary>
/// 扩展仓储
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public interface IExtentionRepository<TEntity>:IRepository<TEntity> where TEntity:class
{
#region 行为
/// <summary>
/// 添加集合
/// </summary>
/// <param name="item"></param>
void Insert(IEnumerable<TEntity> item);
/// <summary>
/// 修改集合
/// </summary>
/// <param name="item"></param>
void Update(IEnumerable<TEntity> item);
/// <summary>
/// 删除集合
/// </summary>
/// <param name="item"></param>
void Delete(IEnumerable<TEntity> item);
#endregion
#region 查询
/// <summary>
/// 根据指定lambda表达式,得到结果集
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
IQueryable<TEntity> GetModel(Expression<Func<TEntity, bool>> predicate);
/// <summary>
/// 根据指定lambda表达式,得到第一个实体
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
TEntity Find(Expression<Func<TEntity, bool>> predicate);
#endregion
}
IExtentionRepository
③:EFRepository EF仓储
namespace:EntityFramework
public class EFRepository<TEntity> :
IRepository<TEntity>,
IExtentionRepository<TEntity>
where TEntity:class
{
#region Properties
/// <summary>
/// EF上下文
/// </summary>
private DbContext EFDbContext;
#endregion
#region Constructors
public EFRepository()
: this(null)
{ }
/// <summary>
/// 带参构造函数
/// </summary>
public EFRepository(DbContext db)
{
EFDbContext = db;
}
#endregion
#region Methods
/// <summary>
/// 提交到数据库
/// </summary>
public void SaveChanges()
{
try
{
EFDbContext.SaveChanges();
}
catch (Exception ex)
{
//保存日志
//抛出异常
throw new MithrilCommonException(ex.Message, ex);
}
}
#endregion
#region IReposiotry<TEntity>
/// <summary>
/// 少量数据插入
/// </summary>
/// <param name="item"></param>
public void Insert(TEntity item)
{
if (item != null)
{
EFDbContext.Entry<TEntity>(item as TEntity);
EFDbContext.Set<TEntity>().Add(item as TEntity);
this.SaveChanges();
}
}
/// <summary>
/// 删除一个实体
/// </summary>
/// <param name="id"></param>
public void Delete(TEntity item)
{
if (item != null)
{
//将实体以"UnChanged"的状态放置到上下文中
EFDbContext.Set<TEntity>().Attach(item as TEntity);
//给定实体标记为“已删除”
EFDbContext.Entry(item).State = EntityState.Deleted;
//EFDbContext.Set<TEntity>().Remove(item as TEntity);
this.SaveChanges();
}
}
/// <summary>
/// 更新一个实体
/// </summary>
/// <param name="item"></param>
public void Update(TEntity item)
{
if(item != null)
{
//将实体以"UnChanged"的状态放置到上下文中
EFDbContext.Set<TEntity>().Attach(item as TEntity);
//更新
EFDbContext.Entry(item).State = EntityState.Modified;
this.SaveChanges();
}
}
/// <summary>
/// 根据id获取实体
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public TEntity Find(params object[] id)
{
return EFDbContext.Set<TEntity>().Find(id);
}
/// <summary>
/// 拿到可查询结果集
/// </summary>
/// <returns></returns>
System.Linq.IQueryable<TEntity> GetModel()
{
return null;
}
//设置数据上下文
public void SetDataContextByResloveName(string contextName)
{
try
{
EFDbContext = ServiceLocator.Instance.GetService<DbContext>(contextName);
}
catch (Exception)
{
throw new ArgumentException("设置EFContext出错");
}
}
/// <summary>
/// 拿到可查询结果集
/// </summary>
/// <returns></returns>
IQueryable<TEntity> IRepository<TEntity>.GetModel()
{
throw new NotImplementedException();
}
#endregion
#region IExtentionRepository
public void Insert(IEnumerable<TEntity> item)
{
foreach (var entity in item)
{
EFDbContext.Entry<TEntity>(entity as TEntity);
EFDbContext.Set<TEntity>().Add(entity as TEntity);
}
this.SaveChanges();
}
public void Update(IEnumerable<TEntity> item)
{
#region 给每个对象改变状态
foreach (var model in item)
{
EFDbContext.Set<TEntity>().Attach(model as TEntity);
EFDbContext.Entry(model).State = EntityState.Modified;
this.SaveChanges();
}
#endregion
}
public void Delete(IEnumerable<TEntity> item)
{
throw new NotImplementedException();
}
public IQueryable<TEntity> GetModel(Expression<Func<TEntity, bool>> predicate)
{
throw new NotImplementedException();
}
public TEntity Find(Expression<Func<TEntity, bool>> predicate)
{
throw new NotImplementedException();
}
#endregion
}
EFRepository
其中抛出的Exception为自定义的异常类
4:CodeFirst迁移
vs17中:视图 > 其他窗口 > 程序包管理控制台
默认项目栏中选择相应的项目,
①:Enable-Migrations -ContextTypeName -Force
为你制定的上下文开始迁移工作,-ContextTypeName 为你的上下文名称,-Force为可选项,是否覆盖你所选的上下文的迁移
运行后,会生成Migration文件夹
②:Add-Migration -MigrationName -Force
当你新建数据库,添加字段、删除、更新字段时,输入此命令,根据你DbContext实现类的策略以及之前对象的约束,CodeFirst会生成数据库以及相应的表
③:Update-DataBase,将改动对应到实体库上
贴一个测试DbContext类
public class EFTestContext : DbContext
{
public EFTestContext()
: base("name=EFTestContext")
{
//模型变更时更新数据库
Database.SetInitializer<EFTestContext>(new CreateDatabaseIfNotExists<EFTestContext>());
}
public DbSet<Book> Book { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Book>().MapToStoredProcedures();
base.OnModelCreating(modelBuilder);
}
}
EFTestContext
5:MVC5 Autofac配置
网上有很多例子,并不符合实际开发,这里重点说一下一个接口有很多实现类的情况,应该如何配置Autofac
①:Global.asax配置
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
IoCConfig();
}
/// <summary>
/// IoC注入
/// </summary>
private void IoCConfig()
{
var builder = new ContainerBuilder();
#region Repository注册
builder.RegisterGeneric(typeof(EFRepository<>)).Named("EFRepository",typeof(IRepository<>)).InstancePerLifetimeScope();
#endregion
#region Service注册
builder.RegisterType(typeof(EFTestContext)).Named("EF", typeof(DbContext)).InstancePerLifetimeScope();
#endregion
//注册 Controller
builder.RegisterControllers(typeof(MvcApplication).Assembly);
var container = builder.Build();
//MVC扩展
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
泛型配置
泛型配置看官方文档
http://docs.autofac.org/en/latest/advanced/adapters-decorators.html
②:ServiceLocator,用于实现同一接口不同实现的Autofac Reslove
public sealed class ServiceLocator
{
#region Constructor
public ServiceLocator()
{
}
#endregion
#region Singleton
private static readonly ServiceLocator _instance = new ServiceLocator();
/// <summary>
/// 实例
/// </summary>
public static ServiceLocator Instance
{
get
{
return _instance;
}
}
#endregion
#region Public Methods
public TEntity GetService<TEntity>(string resloverName)
{
return AutofacDependencyResolver.Current.RequestLifetimeScope.ResolveNamed<TEntity>(resloverName);
}
#endregion
}
ServiceLocator
6:MVC Web测试
//获取指定的IoC实例
//Author:Yannefer716
IRepository<Book> bookRepository = ServiceLocator.Instance.GetService<IRepository<Book>>("EFRepository");
#endregion
public HomeController()
{
}
public ActionResult Index()
{
var Book = new Book()
{
BookCode = ,
BookName = "Test"
};
bookRepository.SetDataContextByResloveName("EF");
bookRepository.Insert(Book);
return View();
}
}
HomeController
由于Autofac注册的是泛型,并不知道具体的实现是哪一个,在注册Controller时需要提供一个无参构造函数。
SetDataContextByResloveName 方法指定是哪个DbContext,可在Global中设置多个Context。
关于Autofac对Mvc具体的实现机制,下篇再讨论。
(转载请注明)
EF6CodeFirst+MVC5+Autofac泛型注册 入门实例的更多相关文章
- autofac如何注册静态方法里的接口对象
标题可能是不准确的,因为我不知道如何描述.不知道的原因,是对依赖注入一知半解. Autofac可以自动注册对象实例到接口,人所尽知.而在asp.net mvc中,这个实例化的工作,通常在每个控制器的构 ...
- Asp.Net MVC2.0 Url 路由入门---实例篇
本篇主要讲述Routing组件的作用,以及举几个实例来学习Asp.Net MVC2.0 Url路由技术. 接着上一篇开始讲,我们在Global.asax中注册一条路由后,我们的请求是怎么转到相应的Vi ...
- mybatis 详解(二)------入门实例(基于XML)
通过上一小节,mybatis 和 jdbc 的区别:http://www.cnblogs.com/ysocean/p/7271600.html,我们对 mybatis有了一个大致的了解,下面我们通过一 ...
- mybatis 详解(三)------入门实例(基于注解)
1.创建MySQL数据库:mybatisDemo和表:user 详情参考:mybatis 详解(二)------入门实例(基于XML) 一致 2.建立一个Java工程,并导入相应的jar包,具体目录如 ...
- jquery实战第一讲---概述及其入门实例
就在5月28号周四下午五点的时候,接到xxx姐姐的电话,您是xxx吗?准备一下,周五上午八点半去远洋面试,一路风尘仆仆,颠颠簸簸,由于小编晕车,带着晕晕乎乎的脑子,小编就稀里糊涂的去面试了,温馨提醒, ...
- Struts1入门实例(简单登录)
Struts1入门实例(简单登录) 现在开始加入公司的核心项目,但由于项目开发比较早,所以使用的技术不是很新潮,前台用的还是struts1. 虽然不是什么新技术,但仍可以从中学到好多东西的.花了一个晚 ...
- Mybatis入门实例
MyBatis 简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis ...
- destoon入门实例与常见问题
收集了一些destoon入门实例与常见问题,大家做个参考. 链接如下: destoon忘记后台密码怎么办?destoon找回管理员密码 忘记destoon管理员后台账号密码怎么办?解决方法 desto ...
- java rmi 入门实例
java rmi 入门实例 (2009-06-16 16:07:55) 转载▼ 标签: java rmi 杂谈 分类: java-基础 java rmi即java远程接口调用,实现了2台虚拟机之 ...
随机推荐
- getHibernateTemplate() VS getSession()
如题所示,对于这个问题,官网文档已给出答案,详见: /** * Obtain a Hibernate Session, either from the current transaction or * ...
- 链表回文判断(C++)
题目描述: 对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构. 给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构.保证链表长度小于等 ...
- SeleniumIDE_初识
版权声明:本文为博主原创文章,转载请注明出处. 学习Selenium,除了自己手动编写脚本,还可以使用Selenium IDE进行脚本录制. 安装Selenium IDE Selenium IDE是F ...
- Phalcon调试大杀器之phalcon-debugbar安装
Phalcon 是一款非常火的高性能C扩展php开发框架.特点是高性能低耦合,但遗憾的是长期缺少一款得力的调试辅助工具. 目前版本主要以Laravel debugbar的具有功能为蓝本开发,并针对ph ...
- 6.C++初步分析类
面向对象的意义在于: -将日常生活中习惯的思维方式引入程序设计中 -将需求中的慨念直观的映射到解决方案中 -以模块为中心构建可复用的软件系统 -提高软件产品的可维护性和可扩展性 其中类和对象是面向对象 ...
- python学习:备份文档并压缩为zip格式
import os import time source = ['/root/notes'] target_dir = '/root/backup' if not os.path.exists(tar ...
- easyui验证扩展
问题描述: 如上所示:当用户添加信息时,必须保证一个队伍一天只能有一条数据.所以在选择了报表日期的时候必须查询数据库里面当前队伍这一天的数据是否存在.如果不存在,即当前日期队伍没有数据,就可以进行数据 ...
- chromedriver与chrome版本映射表(最新)
selenium想在chrome进行跑,前提需要下载chromedriver,以下整理了chromedriver与chrome的对应关系表 chromedriver(下载地址):http://chro ...
- 移动端页面点击a标签会有半透明的阴影或红色边框的bug
好久没有更新了,今天来一发 ^_^ 最近在写移动端页面,测试时发现一个a标签的bug:无论是iOS端还是Android端都存在,当点击a标签,会有一个矩形的透明的阴影闪一下(不同的浏览器阴影的颜色还不 ...
- C#中引用变量是否应该加ref?
看如下代码: void Test(T t); void Test(ref T t); 当T是值类型的时候,很好判断,第一种并不能改变方法外变量的值,需要第二种方法才可以.通过查看IL代码,可以看到 ...