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台虚拟机之 ...
随机推荐
- HDU3488 Tour [有向环覆盖 费用流]
Tour Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Submis ...
- Linux 常用命令 (common commands for linux)
Linux 常用命令 (Common Commands For Linux) 1.声明,此文章仅写基于 Bash shell 常用的命令,如果遇上命令在使用过程中提示没有,可能随着更新,命令也被替换掉 ...
- Composer 结合 Git 创建 “服务类库”
Composer 结合 Git 创建 "服务类库" 我一直认为,现在的 PHP 已经进展到了工程化的领域.以前的 PHP 开发者,以快为美,速度和规模永远都是矛盾体.现在的 PHP ...
- 解决无法make uImage的问题
进入一个uboot目录, 执行make distclean make at91sam9260ek_config make ARCH=arm CROSS_COMPILE=arm-linux- cp to ...
- 用Android属性动画实现和演示迪士尼动画基本原则
本文将介绍在Android平台上实现和演示迪士尼动画基本准则. 项目开源,GitHub: https://github.com/vhow/animation 说明: 演示动画原则的想法源自 Anima ...
- 《Discuz安装时候出现乱码 -- 问题解决方法》
自我安装discuz时出现安装界面乱码的情况,跟链接所说一样,经过原作的分享,加上我自己的实验,明白了,什么时候修改/usr/local/php/etc/php.ini里面的default_chars ...
- python学习:函数传参数
#!/usr/bin/python import sys def isNum(s): for i in s: if i in '0123456789': ...
- 【Unity3D技术文档翻译】第1.9篇 使用 Unity AssetBundle Browser tool (AssetBundle系列完结)
上一章:[Unity3D技术文档翻译]第1.8篇 AssetBundles 问题及解决方法 本章原文所在章节:[Unity Manual]→[Working in Unity]→[Advanced D ...
- linux 下安装php curl扩展
方法一 安装cURL wget https://curl.haxx.se/download/curl-7.53.1.tar.gz tar -zxf curl-7.17.1.tar.gz ./confi ...
- 相对路径和绝对路径的问题"/"带不带斜杠
带有"/"是绝对路径,为项目的上下文目录是从工程开始的路径 不带的话是一个相对路径,相对于执行该代码的目录文件结构