贴一个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. BZOJ 3505: [Cqoi2014]数三角形 [组合计数]

    3505: [Cqoi2014]数三角形 给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个. 注意三角形的三点不能共线. 1<=m,n<=1000 $n++ m++$ $ans ...

  2. LNMP环境下搭建wordpress

    WordPress 下载WordPress安装包,可以直接wget获取也可以ftp上传,解压到/usr/share/nginx/html/blog-wp,访问index.php即进行安装:   wor ...

  3. ipset批量配置iptables

    简介: ipset是iptables的扩展,允许你创建匹配整个地址sets(地址集合)的规则.而不像普通的iptables链是线性的存储和过滤,ip集合存储在带索引的数据结构中,这种集合比较大也可以进 ...

  4. CentOS 7 NetworkManager Keeps Overwriting /etc/resolv.conf

    In CentOS or Red Hat Enterprise Linux (RHEL) 7, you can find your /etc/resolv.conf file, which holds ...

  5. Conemu, Msys2 工具整合,提升windows下控制台工作效率

    与windows cmd相比较git-bash这类的console工具好用很多,但是git-bash的命令和功能相对简单,功能扩展起来不方便,git-bash本身也是基于msys的. 昨天发现使用Ms ...

  6. (MonoGame从入门到放弃-2) 初识MonoGame

    上一节记录了大致的搭建MonoGame的环境,默认大家都是都是使用过Visual Studio的,没使用过的话,可以去https://www.visualstudio.com/下载一个试试,社区版免费 ...

  7. Java语言的特性

    一.跨平台 借助虚拟机,程序不经修改即可在不同硬件或者软件平台上运行.源代码级(C,C++源码会重新编译),目标代码级(Java). 二.面向对象 以对象为基本单位,使得程序开发变得简单易用,拓展更方 ...

  8. QT creator 其他资源(image)的添加以及简单利用

    QT creator 添加一些资源文件  :https://www.cnblogs.com/cszlg/p/3234786.html(转自园子) 补充: 补充:如果要给生成的exe可执行文件更换一个自 ...

  9. Dropout

    参数正则化方法 - Dropout 受人类繁衍后代时男女各一半基因进行组合产生下一代的启发,论文(paper.pdf)提出了Dropout. Dropout是一种在深度学习环境中应用的正规化手段.它是 ...

  10. Mysql group by,order by,dinstict优化

    1.order by优化 2.group by优化 3.Dinstinct 优化 1.order by优化 实现方式: 1. 根据索引字段排序,利用索引取出的数据已经是排好序的,直接返回给客户端: 2 ...