EF6CodeFirst+MVC5+Autofac泛型注册 入门实例
2018-06-22 06:19:27来源:未知 阅读 ()
贴一个EF6 CodeFirst模式结合MVC5和Autofac(泛型注册)的一个入门实例
网上类似的例子实在太少,最近自己也有用到这一块的知识,总结了一下,不要让后人踩了自己踩过的坑。
1:新建三个项目,Web(MVC)、EntityFramework类库(EF框架)、Core类库(核心框架),nuget EntityFramework,Autofac,AutofacMvc5
2:建立简单对象:书籍(Book)Model,继承主键为Int的基类
①:接口
namespace:Core.Domain.Interface
1 /// <summary> 2 /// 实体对象接口 3 /// </summary> 4 public interface IEntity<PrimaryKeyType> 5 { 6 /// <summary> 7 /// 主键 8 /// </summary> 9 PrimaryKeyType Id { get; } 10 }
②:基类
namespace:Core.Domain.Base
1 /// <summary> 2 /// Int抽象基类 3 /// </summary> 4 /// <typeparam name="Type"></typeparam> 5 public abstract class EntityBase : Interface.IEntity<int> 6 { 7 #region Properties 8 9 /// <summary> 10 /// 数据状态 11 /// </summary> 12 public Enum.EntityEnumType Status { get; set; } 13 14 public DateTime CreateDate { get; set; } 15 16 public DateTime UpdateDate { get; set; } 17 18 /// <summary> 19 /// 主键 20 /// </summary> 21 [Key] 22 public int Id { get; set; } 23 #endregion 24 25 #region Constructor 26 public EntityBase() :this(Enum.EntityEnumType.Normal,DateTime.Now,DateTime.Now) 27 { } 28 29 /// <summary> 30 /// 带参初始化 31 /// </summary> 32 public EntityBase(Enum.EntityEnumType _status,DateTime _createDate,DateTime _updateDate) 33 { 34 Status = _status; 35 CreateDate = _createDate; 36 UpdateDate = _updateDate; 37 } 38 #endregion 39 40 #region Methods 41 42 #endregion 43 44 }
③:书籍类
namespace:Web.Models
1 [Table("Book")]//表名 2 /// <summary> 3 /// 实体—书籍 4 /// </summary> 5 public class Book:EntityBase 6 { 7 #region Constructor 8 public Book() 9 : base() 10 { } 11 #endregion 12 13 #region Fileds 14 /// <summary> 15 /// 书籍编号 16 /// </summary> 17 [DisplayName("书籍编号")] 18 public int BookCode { get; set; } 19 20 /// <summary> 21 /// 书名 22 /// </summary> 23 [DisplayName("书名")] 24 [MaxLength(50,ErrorMessage = "书名过长"),MinLength(2,ErrorMessage = "书名过短")] 25 public string BookName { get; set; } 26 27 /// <summary> 28 /// 作者 29 /// </summary> 30 [MaxLength(50,ErrorMessage = "作者姓名过长")] 31 [DisplayName("作者")] 32 public string Author { get; set; } 33 34 #endregion 35 36 #region 导航属性 37 38 #endregion 39 40 41 #region IEntity成员 42 #endregion 43 }
解释一下类的配置
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
1 public interface IRepository<TEntity> where TEntity:class 2 { 3 /// <summary> 4 /// 添加一个对象 5 /// </summary> 6 /// <param name="item"></param> 7 void Insert(TEntity item); 8 9 /// <summary> 10 /// 删除一个对象 11 /// </summary> 12 void Delete(TEntity item); 13 14 /// <summary> 15 /// 更新一个对象 16 /// </summary> 17 void Update(TEntity item); 18 19 /// <summary> 20 /// 通过主键取对象 21 /// </summary> 22 /// <returns></returns> 23 TEntity Find(params object[] id); 24 25 /// <summary> 26 /// 拿到可查询结果集 27 /// </summary> 28 /// <returns></returns> 29 System.Linq.IQueryable<TEntity> GetModel(); 30 31 /// <summary> 32 /// 设置数据上下文 33 /// </summary> 34 /// <param name="db"></param> 35 void SetDataContextByResloveName(string dbContext); 36 }
SetDataContextByResloveName这个方法,到下文的Autofac配置时再说
②:IExtentionRepository 扩展
namespace:Core.IExtentionRepository
1 /// <summary> 2 /// 扩展仓储 3 /// </summary> 4 /// <typeparam name="TEntity"></typeparam> 5 public interface IExtentionRepository<TEntity>:IRepository<TEntity> where TEntity:class 6 { 7 #region 行为 8 /// <summary> 9 /// 添加集合 10 /// </summary> 11 /// <param name="item"></param> 12 void Insert(IEnumerable<TEntity> item); 13 /// <summary> 14 /// 修改集合 15 /// </summary> 16 /// <param name="item"></param> 17 void Update(IEnumerable<TEntity> item); 18 /// <summary> 19 /// 删除集合 20 /// </summary> 21 /// <param name="item"></param> 22 void Delete(IEnumerable<TEntity> item); 23 #endregion 24 25 #region 查询 26 /// <summary> 27 /// 根据指定lambda表达式,得到结果集 28 /// </summary> 29 /// <param name="predicate"></param> 30 /// <returns></returns> 31 IQueryable<TEntity> GetModel(Expression<Func<TEntity, bool>> predicate); 32 33 /// <summary> 34 /// 根据指定lambda表达式,得到第一个实体 35 /// </summary> 36 /// <param name="predicate"></param> 37 /// <returns></returns> 38 TEntity Find(Expression<Func<TEntity, bool>> predicate); 39 #endregion 40 }
③:EFRepository EF仓储
namespace:EntityFramework
1 public class EFRepository<TEntity> : 2 IRepository<TEntity>, 3 IExtentionRepository<TEntity> 4 where TEntity:class 5 { 6 #region Properties 7 /// <summary> 8 /// EF上下文 9 /// </summary> 10 private DbContext EFDbContext; 11 #endregion 12 13 #region Constructors 14 public EFRepository() 15 : this(null) 16 { } 17 18 /// <summary> 19 /// 带参构造函数 20 /// </summary> 21 public EFRepository(DbContext db) 22 { 23 EFDbContext = db; 24 } 25 #endregion 26 27 #region Methods 28 /// <summary> 29 /// 提交到数据库 30 /// </summary> 31 public void SaveChanges() 32 { 33 try 34 { 35 EFDbContext.SaveChanges(); 36 } 37 catch (Exception ex) 38 { 39 //保存日志 40 //抛出异常 41 throw new MithrilCommonException(ex.Message, ex); 42 } 43 } 44 45 46 #endregion 47 48 #region IReposiotry<TEntity> 49 50 /// <summary> 51 /// 少量数据插入 52 /// </summary> 53 /// <param name="item"></param> 54 public void Insert(TEntity item) 55 { 56 if (item != null) 57 { 58 EFDbContext.Entry<TEntity>(item as TEntity); 59 EFDbContext.Set<TEntity>().Add(item as TEntity); 60 this.SaveChanges(); 61 } 62 } 63 64 /// <summary> 65 /// 删除一个实体 66 /// </summary> 67 /// <param name="id"></param> 68 public void Delete(TEntity item) 69 { 70 if (item != null) 71 { 72 //将实体以"UnChanged"的状态放置到上下文中 73 EFDbContext.Set<TEntity>().Attach(item as TEntity); 74 //给定实体标记为“已删除” 75 EFDbContext.Entry(item).State = EntityState.Deleted; 76 //EFDbContext.Set<TEntity>().Remove(item as TEntity); 77 this.SaveChanges(); 78 } 79 } 80 81 /// <summary> 82 /// 更新一个实体 83 /// </summary> 84 /// <param name="item"></param> 85 public void Update(TEntity item) 86 { 87 if(item != null) 88 { 89 //将实体以"UnChanged"的状态放置到上下文中 90 EFDbContext.Set<TEntity>().Attach(item as TEntity); 91 //更新 92 EFDbContext.Entry(item).State = EntityState.Modified; 93 this.SaveChanges(); 94 } 95 } 96 97 /// <summary> 98 /// 根据id获取实体 99 /// </summary> 100 /// <param name="id"></param> 101 /// <returns></returns> 102 public TEntity Find(params object[] id) 103 { 104 return EFDbContext.Set<TEntity>().Find(id); 105 } 106 107 /// <summary> 108 /// 拿到可查询结果集 109 /// </summary> 110 /// <returns></returns> 111 System.Linq.IQueryable<TEntity> GetModel() 112 { 113 return null; 114 } 115 116 //设置数据上下文 117 public void SetDataContextByResloveName(string contextName) 118 { 119 try 120 { 121 EFDbContext = ServiceLocator.Instance.GetService<DbContext>(contextName); 122 } 123 catch (Exception) 124 { 125 throw new ArgumentException("设置EFContext出错"); 126 } 127 128 } 129 130 /// <summary> 131 /// 拿到可查询结果集 132 /// </summary> 133 /// <returns></returns> 134 IQueryable<TEntity> IRepository<TEntity>.GetModel() 135 { 136 throw new NotImplementedException(); 137 } 138 139 140 #endregion 141 142 #region IExtentionRepository 143 public void Insert(IEnumerable<TEntity> item) 144 { 145 foreach (var entity in item) 146 { 147 EFDbContext.Entry<TEntity>(entity as TEntity); 148 EFDbContext.Set<TEntity>().Add(entity as TEntity); 149 } 150 this.SaveChanges(); 151 } 152 153 public void Update(IEnumerable<TEntity> item) 154 { 155 #region 给每个对象改变状态 156 foreach (var model in item) 157 { 158 EFDbContext.Set<TEntity>().Attach(model as TEntity); 159 EFDbContext.Entry(model).State = EntityState.Modified; 160 this.SaveChanges(); 161 } 162 #endregion 163 } 164 165 public void Delete(IEnumerable<TEntity> item) 166 { 167 throw new NotImplementedException(); 168 } 169 170 public IQueryable<TEntity> GetModel(Expression<Func<TEntity, bool>> predicate) 171 { 172 throw new NotImplementedException(); 173 } 174 175 public TEntity Find(Expression<Func<TEntity, bool>> predicate) 176 { 177 throw new NotImplementedException(); 178 } 179 #endregion 180 }
其中抛出的Exception为自定义的异常类
4:CodeFirst迁移
vs17中:视图 > 其他窗口 > 程序包管理控制台
默认项目栏中选择相应的项目,
①:Enable-Migrations -ContextTypeName -Force
为你制定的上下文开始迁移工作,-ContextTypeName 为你的上下文名称,-Force为可选项,是否覆盖你所选的上下文的迁移
运行后,会生成Migration文件夹
②:Add-Migration -MigrationName -Force
当你新建数据库,添加字段、删除、更新字段时,输入此命令,根据你DbContext实现类的策略以及之前对象的约束,CodeFirst会生成数据库以及相应的表
③:Update-DataBase,将改动对应到实体库上
贴一个测试DbContext类
1 public class EFTestContext : DbContext 2 { 3 4 public EFTestContext() 5 : base("name=EFTestContext") 6 { 7 //模型变更时更新数据库 8 Database.SetInitializer<EFTestContext>(new CreateDatabaseIfNotExists<EFTestContext>()); 9 } 10 11 public DbSet<Book> Book { get; set; } 12 13 protected override void OnModelCreating(DbModelBuilder modelBuilder) 14 { 15 modelBuilder.Entity<Book>().MapToStoredProcedures(); 16 base.OnModelCreating(modelBuilder); 17 } 18 }
5:MVC5 Autofac配置
网上有很多例子,并不符合实际开发,这里重点说一下一个接口有很多实现类的情况,应该如何配置Autofac
①:Global.asax配置
1 protected void Application_Start() 2 { 3 AreaRegistration.RegisterAllAreas(); 4 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 5 RouteConfig.RegisterRoutes(RouteTable.Routes); 6 BundleConfig.RegisterBundles(BundleTable.Bundles); 7 8 IoCConfig(); 9 } 10 11 /// <summary> 12 /// IoC注入 13 /// </summary> 14 private void IoCConfig() 15 { 16 var builder = new ContainerBuilder(); 17 #region Repository注册 18 builder.RegisterGeneric(typeof(EFRepository<>)).Named("EFRepository",typeof(IRepository<>)).InstancePerLifetimeScope(); 19 #endregion 20 21 #region Service注册 22 builder.RegisterType(typeof(EFTestContext)).Named("EF", typeof(DbContext)).InstancePerLifetimeScope(); 23 #endregion 24 25 //注册 Controller 26 builder.RegisterControllers(typeof(MvcApplication).Assembly); 27 var container = builder.Build(); 28 //MVC扩展 29 DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 30 }
泛型配置看官方文档
http://docs.autofac.org/en/latest/advanced/adapters-decorators.html
②:ServiceLocator,用于实现同一接口不同实现的Autofac Reslove
1 public sealed class ServiceLocator 2 { 3 #region Constructor 4 public ServiceLocator() 5 { 6 7 } 8 #endregion 9 10 #region Singleton 11 private static readonly ServiceLocator _instance = new ServiceLocator(); 12 13 /// <summary> 14 /// 实例 15 /// </summary> 16 public static ServiceLocator Instance 17 { 18 get 19 { 20 return _instance; 21 } 22 } 23 #endregion 24 25 #region Public Methods 26 public TEntity GetService<TEntity>(string resloverName) 27 { 28 return AutofacDependencyResolver.Current.RequestLifetimeScope.ResolveNamed<TEntity>(resloverName); 29 } 30 #endregion 31 }
6:MVC Web测试
1 //获取指定的IoC实例 2 //Author:Yannefer716 3 IRepository<Book> bookRepository = ServiceLocator.Instance.GetService<IRepository<Book>>("EFRepository"); 4 5 #endregion 6 public HomeController() 7 { 8 9 } 10 11 public ActionResult Index() 12 { 13 var Book = new Book() 14 { 15 BookCode = 1, 16 BookName = "Test" 17 }; 18 bookRepository.SetDataContextByResloveName("EF"); 19 bookRepository.Insert(Book); 20 21 return View(); 22 } 23 }
由于Autofac注册的是泛型,并不知道具体的实现是哪一个,在注册Controller时需要提供一个无参构造函数。
SetDataContextByResloveName 方法指定是哪个DbContext,可在Global中设置多个Context。
关于Autofac对Mvc具体的实现机制,下篇再讨论。
(转载请注明)
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- .NET微信开发之PC 端微信扫码注册和登录功能实现 2020-02-23
- 深入浅析.NET应用程序SQL注入 2020-02-23
- .NET CORE动态调用泛型方法详解 2019-12-31
- MvcPager分页控件使用注意事项 2019-11-01
- 如何取得Repeater控件选择的项目及注意事项 2019-10-08
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash