贴一个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泛型注册 入门实例的更多相关文章

  1. autofac如何注册静态方法里的接口对象

    标题可能是不准确的,因为我不知道如何描述.不知道的原因,是对依赖注入一知半解. Autofac可以自动注册对象实例到接口,人所尽知.而在asp.net mvc中,这个实例化的工作,通常在每个控制器的构 ...

  2. Asp.Net MVC2.0 Url 路由入门---实例篇

    本篇主要讲述Routing组件的作用,以及举几个实例来学习Asp.Net MVC2.0 Url路由技术. 接着上一篇开始讲,我们在Global.asax中注册一条路由后,我们的请求是怎么转到相应的Vi ...

  3. mybatis 详解(二)------入门实例(基于XML)

    通过上一小节,mybatis 和 jdbc 的区别:http://www.cnblogs.com/ysocean/p/7271600.html,我们对 mybatis有了一个大致的了解,下面我们通过一 ...

  4. mybatis 详解(三)------入门实例(基于注解)

    1.创建MySQL数据库:mybatisDemo和表:user 详情参考:mybatis 详解(二)------入门实例(基于XML) 一致 2.建立一个Java工程,并导入相应的jar包,具体目录如 ...

  5. jquery实战第一讲---概述及其入门实例

    就在5月28号周四下午五点的时候,接到xxx姐姐的电话,您是xxx吗?准备一下,周五上午八点半去远洋面试,一路风尘仆仆,颠颠簸簸,由于小编晕车,带着晕晕乎乎的脑子,小编就稀里糊涂的去面试了,温馨提醒, ...

  6. Struts1入门实例(简单登录)

    Struts1入门实例(简单登录) 现在开始加入公司的核心项目,但由于项目开发比较早,所以使用的技术不是很新潮,前台用的还是struts1. 虽然不是什么新技术,但仍可以从中学到好多东西的.花了一个晚 ...

  7. Mybatis入门实例

    MyBatis 简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis ...

  8. destoon入门实例与常见问题

    收集了一些destoon入门实例与常见问题,大家做个参考. 链接如下: destoon忘记后台密码怎么办?destoon找回管理员密码 忘记destoon管理员后台账号密码怎么办?解决方法 desto ...

  9. java rmi 入门实例

    java rmi 入门实例 (2009-06-16 16:07:55) 转载▼ 标签: java rmi 杂谈 分类: java-基础    java rmi即java远程接口调用,实现了2台虚拟机之 ...

随机推荐

  1. HDU3488 Tour [有向环覆盖 费用流]

    Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

  2. Linux 常用命令 (common commands for linux)

    Linux 常用命令 (Common Commands For Linux) 1.声明,此文章仅写基于 Bash shell 常用的命令,如果遇上命令在使用过程中提示没有,可能随着更新,命令也被替换掉 ...

  3. Composer 结合 Git 创建 “服务类库”

    Composer 结合 Git 创建 "服务类库" 我一直认为,现在的 PHP 已经进展到了工程化的领域.以前的 PHP 开发者,以快为美,速度和规模永远都是矛盾体.现在的 PHP ...

  4. 解决无法make uImage的问题

    进入一个uboot目录, 执行make distclean make at91sam9260ek_config make ARCH=arm CROSS_COMPILE=arm-linux- cp to ...

  5. 用Android属性动画实现和演示迪士尼动画基本原则

    本文将介绍在Android平台上实现和演示迪士尼动画基本准则. 项目开源,GitHub: https://github.com/vhow/animation 说明: 演示动画原则的想法源自 Anima ...

  6. 《Discuz安装时候出现乱码 -- 问题解决方法》

    自我安装discuz时出现安装界面乱码的情况,跟链接所说一样,经过原作的分享,加上我自己的实验,明白了,什么时候修改/usr/local/php/etc/php.ini里面的default_chars ...

  7. python学习:函数传参数

    #!/usr/bin/python   import sys   def isNum(s):     for i in s:         if i in '0123456789':         ...

  8. 【Unity3D技术文档翻译】第1.9篇 使用 Unity AssetBundle Browser tool (AssetBundle系列完结)

    上一章:[Unity3D技术文档翻译]第1.8篇 AssetBundles 问题及解决方法 本章原文所在章节:[Unity Manual]→[Working in Unity]→[Advanced D ...

  9. 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 ...

  10. 相对路径和绝对路径的问题"/"带不带斜杠

    带有"/"是绝对路径,为项目的上下文目录是从工程开始的路径 不带的话是一个相对路径,相对于执行该代码的目录文件结构