本话题是根据郭明峰博客《MVC实用架构系列》的搭建学习总结。

一、数据仓储访问的构建

充分采用面向对象思想,针对接口、针对抽象进行设计;

1.UnitOfWork的构建

最终使得所有的数据操作最终都提交到一个与IUnitOfWork接口的实现类中进行操作,以保证各个实体的Repository与IUnitOfWork使用的是同一个DbContext上下文

2.Repository的构建

注:EF的操作提交 context.SaveChanged() 默认就是事务性的,只要保证了当前的所有实体的操作都是在一个共同的上下文中进行的,就实现了事务操作了

3.使用MEF应用IOC

(1)优势

.net4.0 自带:MEF的功能在 System.ComponentModel.Composition.dll 程序集中,直接引用即可使用,不用安装第三方组件

0 配置:MEF是不需要使用配置文件或代码对接口与实现进行一一配对的,只需要简单的使用几个Attribute特性,就能自动完成源与目标的配对工作

自动化:系统初始化时自动遍历程序目录或指定文件夹下的dll,根据程序集中接口与类的特定Attribute特性进行自动配对

(2)使用

-->在接口和类上加上特定的Attribute,

例如:使用[Export(typeof(IUnitOfWork))]将EFUnitOfWorkContext进行导出

  1. [Export(typeof(IUnitOfWork))]
  2. internal class EFUnitOfWorkContext : UnitOfWorkContextBase

使用[Import],在需要EFUnitOfWorkContext时直接将其导入

 

  1. [Import]
  2. protected IUnitOfWork UnitOfWork { get; set; }

(3)MVC项目的应用

IOC组件是通过 DependencyResolver类中的 SetResolver(IDependencyResolver resolver) 方法来向MVC提供注册点的,所以我们只需要实现一个 IDependencyResolver 接口的MEF实现类,即可完成MEF在MVC中的注册工作。

  1. /// <summary>
  2. /// MEF依赖关系解析类
  3. /// </summary>
  4. public class MefDependencySolver : IDependencyResolver
  5. {
  6. private readonly ComposablePartCatalog _catalog;
  7. private const string HttpContextKey = "MefContainerKey";
  8.  
  9. public MefDependencySolver(ComposablePartCatalog catalog)
  10. {
  11. _catalog = catalog;
  12. }
  13.  
  14. public CompositionContainer Container
  15. {
  16. get
  17. {
  18. if (!HttpContext.Current.Items.Contains(HttpContextKey))
  19. {
  20. HttpContext.Current.Items.Add(HttpContextKey, new CompositionContainer(_catalog));
  21. }
  22. CompositionContainer container = (CompositionContainer)HttpContext.Current.Items[HttpContextKey];
  23. HttpContext.Current.Application["Container"] = container;
  24. return container;
  25. }
  26. }
  27.  
  28. #region IDependencyResolver Members
  29.  
  30. public object GetService(Type serviceType)
  31. {
  32. string contractName = AttributedModelServices.GetContractName(serviceType);
  33. return Container.GetExportedValueOrDefault<object>(contractName);
  34. }
  35.  
  36. public IEnumerable<object> GetServices(Type serviceType)
  37. {
  38. return Container.GetExportedValues<object>(serviceType.FullName);
  39. }
  40.  
  41. #endregion
  42. }

(4)MEF排错

-->MEF的导出导入是整体关联的,只要树中某一个部件匹配失败,整个树将无法实例化,也就是会出现Import的属性值为Null

使用MEF开发团队提供的调试工具MEFX来进行调试

-->常用命令

1.基本语法

mefx [files and directories] [action] [options]

       2.列出可用部件

       (1)mefx /file:【dll路径】 /parts

ex: F:\study\资源包\Ioc\mefx_0.4>mefx /file:【dll路径】/parts

(2)查看详细信息

mefx /file:【dll路径】 /type:【具体部件名称】 verbose

ex: F:\study\资源包\Ioc\mefx_0.4>mefx /file:【dll路径】 /type:【具体部件名称】 /verbose

(3)列出导入、导出

mefx /file:【dll路径】 /importers(exporters):【具体部件名称】

3.查找拒绝部件

mefx /file:【dll路径】 /rejected /verbose

4.DBContext

(1)实体映射配置

-->映射配置通用接口

  1. /// <summary>
  2. /// 实体映射接口
  3. /// </summary>
  4. [InheritedExport]
  5. public interface IEntityMapper
  6. {
  7. /// <summary>
  8. /// 将当前实体映射对象注册到当前数据访问上下文实体映射配置注册器中
  9. /// </summary>
  10. /// <param name="configurations"></param>
  11. void RegistTo(ConfigurationRegistrar configurations);
  12. }

IEntityMapper接口添加了MEF的InheritedExport特性,该特性可以沿着继承链传递所施加的特性。在需要的时候,就可以通过ImportManyAttribute一次性导出所有实现了IEntityMapper接口的实现类对象。

-->实体映射类

  1. internal partial class RoleConfiguration : EntityTypeConfiguration<Role>,IEntityMapper
  2. {
  3. /// <summary>
  4. /// 实体类-数据表映射构造函数——角色信息
  5. /// </summary>
  6. public RoleConfiguration()
  7. {
  8. RoleConfigurationAppend();
  9. }
  10.  
  11. /// <summary>
  12. /// 额外的数据映射
  13. /// </summary>
  14. partial void RoleConfigurationAppend();
  15.  
  16. /// <summary>
  17. /// 将当前实体映射对象注册到当前数据访问上下文实体映射配置注册器中
  18. /// </summary>
  19. /// <param name="configurations">实体映射配置注册器</param>
  20. public void RegistTo(ConfigurationRegistrar configurations)
  21. {
  22. configurations.Add(this);
  23. }
  24. }

 

(2)EFDbContext

  1. namespace Xwb.Component.Data
  2. {
  3. [Export("EF",typeof(DbContext))]
  4. public class EFDbContext : DbContext
  5. {
  6. #region 构造函数
  7.  
  8. /// <summary>
  9. /// 初始化一个 使用连接名为“default”的数据访问上下文类 的新实例
  10. /// </summary>
  11. public EFDbContext()
  12. : base("default"){}
  13.  
  14. public EFDbContext(string nameOrConnectionString)
  15. : base(nameOrConnectionString){}
  16.  
  17. public EFDbContext(DbConnection existingConnection)
  18. : base(existingConnection, true) { }
  19.  
  20. #endregion
  21.  
  22. [ImportMany(typeof(IEntityMapper))]
  23. public IEnumerable<IEntityMapper> EntityMappers { get; set; }
  24.  
  25. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  26. {
  27. modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
  28. if (EntityMappers == null)
  29. {
  30. return;
  31. }
  32. foreach (var entityMapper in EntityMappers)
  33. {
  34. entityMapper.RegistTo(modelBuilder.Configurations);
  35. }
  36. }
  37. }
  38. }

至此我们有了依托于EF的DBContext上下文对象了。

(3)EFCachingDbContext

接下来我们利用Community Entity Framework Provider Wrappers来完成EF4、5的缓存扩展,构建一个带缓存的EFDbContext

  1. /// <summary>
  2. /// 启用缓存的自定义EntityFramework数据访问上下文
  3. /// </summary>
  4. [Export("EFCaching", typeof(DbContext))]
  5. public class EFCachingDbContext:EFDbContext
  6. {
  7. private static readonly InMemoryCache InMemoryCache= new InMemoryCache();
  8.  
  9. public EFCachingDbContext()
  10. : base(CreateConnectionWrapper("default")){}
  11.  
  12. public EFCachingDbContext(string connectionStringName)
  13. : base(CreateConnectionWrapper(connectionStringName)) { }
  14.  
  15. /// <summary>
  16. /// 由数据库连接字符串创建连接对象
  17. /// </summary>
  18. /// <param name="connectionStringName">连接字符串名称</param>
  19. /// <returns></returns>
  20. private static DbConnection CreateConnectionWrapper(string connectionStringName)
  21. {
  22. PublicHelper.CheckArgument(connectionStringName, "connectionStringName");
  23. string providerInvariantName = "System.Data.SqlClient";
  24. string connectionString = null;
  25. ConnectionStringSettings connectionStringSetting = ConfigurationManager.ConnectionStrings[connectionStringName];
  26. if (connectionStringSetting != null)
  27. {
  28. providerInvariantName = connectionStringSetting.ProviderName;
  29. connectionString = connectionStringSetting.ConnectionString;
  30. }
  31. if (connectionString == null)
  32. {
  33. throw PublicHelper.ThrowComponentException("名称为“" + connectionStringName + "”数据库连接串的ConnectionString值为空。");
  34. }
  35. string wrappedConnectionString = "wrappedProvider=" + providerInvariantName + ";" + connectionString;
  36. EFCachingConnection connection = new EFCachingConnection
  37. {
  38. ConnectionString = wrappedConnectionString,
  39. //这里缓存策略使用了缓存所有数据(CacheAllPolicy)的策略,在实际项目中,最好自定义缓存策略,而不要使用这个策略,以免服务器内存被撑爆。
  40. CachingPolicy = CachingPolicy.CacheAll,
  41. Cache = InMemoryCache
  42. };
  43. return connection;
  44. }
  45. }

(4)根据配置来获得当前数据库访问上下文对象

  1. [Export(typeof(IUnitOfWork))]
  2. internal class EFUnitOfWorkContext : UnitOfWorkContextBase
  3. {
  4. [Import("EF", typeof(DbContext))]
  5. private Lazy<EFDbContext> EFDbContext { get; set; }
  6.  
  7. [Import("EFCaching", typeof(DbContext))]
  8. private Lazy<EFCachingDbContext> EFCachingDbContext { get; set; }
  9.  
  10. /// <summary>
  11. /// 获得 当前使用的数据库访问上下文对象
  12. /// </summary>
  13. protected override DbContext Context
  14. {
  15. get
  16. {
  17. bool secondCachingEnabled = ConfigurationManager.AppSettings["EntityFrameworkCachingEnabled"].CastTo(false);
  18. return secondCachingEnabled ? EFCachingDbContext.Value : EFDbContext.Value;
  19. }
  20. }
  21. }

二、T4模板的运用

1.两个VS插件

Devart T4 Editor:为VS提供智能提示功能。

T4 Toolbox:生成多文件

2.T4模型类

  1. /// <summary>
  2. /// T4实体模型信息类
  3. /// </summary>
  4. public class T4ModelInfo
  5. {
  6. /// <summary>
  7. /// 获取 是否使用模块文件夹
  8. /// </summary>
  9. public bool UseModuleDir { get; private set; }
  10.  
  11. /// <summary>
  12. /// 获取 模型所在模块名称
  13. /// </summary>
  14. public string ModuleName { get; private set; }
  15.  
  16. /// <summary>
  17. /// 获取 模型名称
  18. /// </summary>
  19. public string Name { get; private set; }
  20.  
  21. /// <summary>
  22. /// 获取 模型描述
  23. /// </summary>
  24. public string Description { get; private set; }
  25.  
  26. /// <summary>
  27. /// 主键类型
  28. /// </summary>
  29. public Type KeyType { get; set; }
  30.  
  31. /// <summary>
  32. /// 主键类型名称
  33. /// </summary>
  34. public string KeyTypeName { get; set; }
  35.  
  36. /// <summary>
  37. /// 获取 属性
  38. /// </summary>
  39. public IEnumerable<PropertyInfo> Properties { get; private set; }
  40.  
  41. /// <summary>
  42. /// 构造函数
  43. /// </summary>
  44. /// <param name="modelType"></param>
  45. /// <param name="useModuleDir"></param>
  46. public T4ModelInfo(Type modelType, bool useModuleDir = false)
  47. {
  48. var @namespace = modelType.Namespace;
  49. if (@namespace == null)
  50. {
  51. return;
  52. }
  53. UseModuleDir = useModuleDir;
  54. if (UseModuleDir)
  55. {
  56. var index = @namespace.LastIndexOf('.') + 1;
  57. ModuleName = @namespace.Substring(index, @namespace.Length - index);
  58. }
  59.  
  60. Name = modelType.Name;
  61. PropertyInfo keyProp = modelType.GetProperty("Id");
  62. KeyType = keyProp.PropertyType;
  63. KeyTypeName = KeyType.Name;
  64.  
  65. var descAttributes = modelType.GetCustomAttributes(typeof(DescriptionAttribute), true);
  66. Description = descAttributes.Length == 1 ? ((DescriptionAttribute)descAttributes[0]).Description : Name;
  67. Properties = modelType.GetProperties();
  68. }
  69. }

3.同时生成多个文件

(1)通过反射的方式拿到定义的所有实体类型信息

  1. //当前文件所在目录的绝对路径
  2. string currentPath= Path.GetDirectoryName(Host.TemplateFile);
  3. //项目的绝对路径
  4. string projectPath= currentPath.Substring(0,currentPath.IndexOf(@"\T4"));
  5. //解决方案的绝对路径
  6. string solutionPath= currentPath.Substring(0,currentPath.IndexOf(@"Xwb.Core.Data"));
  7. //加载模型实体
  8. string modelFile= Path.Combine(solutionPath,@"Xwb.Core.Models\bin\Debug\Xwb.Core.Models.dll");
  9. byte[] fileData= File.ReadAllBytes(modelFile);
  10. Assembly assembly = Assembly.Load(fileData);
  11. //调用方通过反射从业务实体程序集中获取所有基类为 EntityBase<int>或EntityBase<Guid> 的并且不是抽象类的实体类型信息
  12. IEnumerable<Type> modelTypes = assembly.GetTypes().Where(m => (typeof(EntityBase<int>).IsAssignableFrom(m) || typeof(EntityBase<Guid>).IsAssignableFrom(m)) && !m.IsAbstract);

 

(2)定义每一个T4 ToolBox模板

  1. public class EntityRepositoryTemplate : CSharpTemplate
  2. {
  3. private T4ModelInfo _model;
  4.  
  5. public EntityRepositoryTemplate(T4ModelInfo model)
  6. {
  7. _model = model;
  8. }
  9.  
  10. public string FileName
  11. {
  12. get
  13. {
  14. return string.Format("{0}Repository.generated.cs",_model.Name);
  15. }
  16. }
  17. public override string TransformText()
  18. {
  19. #>
  20. using System;
  21. using System.ComponentModel.Composition;
  22. using Xwb.Component.Data;
  23. using Xwb.Core.Models<#= _model.UseModuleDir ? "." + _model.ModuleName : null #>;
  24.  
  25. namespace Xwb.Core.Data.Repositories<#= _model.UseModuleDir ? "." + _model.ModuleName : null #>.Impl
  26. {
  27. /// <summary>
  28. /// 仓储操作实现--<#= _model.Description #>
  29. /// </summary>
  30. [Export(typeof(I<#= _model.Name #>Repository))]
  31. public partial class <#= _model.Name #>Repository : EFRepositoryBase<<#= _model.Name #>, <#= _model.KeyTypeName #>>, I<#= _model.Name #>Repository
  32. { }
  33. }
  34. <#+
  35. return this.GenerationEnvironment.ToString();
  36. }
  37. }
  38. #>

 

(3)循环调用每个模板,一次性在不同目录下生成多个文件

  1. foreach(Type modelType in modelTypes)
  2. {
  3. T4ModelInfo model = new T4ModelInfo(modelType, true);
  4.  
  5. //实体映射类
  6. EntityConfigurationTemplate config = new EntityConfigurationTemplate(model);
  7. string path = model.UseModuleDir
  8. ? string.Format(@"{0}\Configurations\{1}", projectPath, model.ModuleName)
  9. : string.Format(@"{0}\Configurations", projectPath);
  10. config.Output.Encoding = Encoding.UTF8;
  11. config.RenderToFile(Path.Combine(path, config.FileName));
  12. }
  13. #>

一周一话题之一(EF-CodeFirst、MEF、T4框架搭建学习)的更多相关文章

  1. EF CodeFirst 使用T4模板 生成文件

    小编是个实用主义者,并没有深入的去理解T4的原理.只是根据自己的需求,在博客园里的前辈哪里找的资料,结合自己的理解,在项目中使用了T4模板. 最近的项目用了他,很方便,节省了不少代码量. 想利用T4做 ...

  2. EF CodeFirst 使用T4模板

    实用等级:★★★★★ 首先,定义一个接口,代表一个领域实体.在定义一个实体集成这个接口,面向接口编程的各种好处就不提了. /// <summary> /// 代表一个领域实体 /// &l ...

  3. EF CodeFirst 创建数据库

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精    话说EF支持三种模式:Code First   M ...

  4. 1.【使用EF Code-First方式和Fluent API来探讨EF中的关系】

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/relationship-in-entity-framework-using-code-firs ...

  5. [.NET领域驱动设计实战系列]专题一:前期准备之EF CodeFirst

    一.前言 从去年已经接触领域驱动设计(Domain-Driven Design)了,当时就想自己搭建一个DDD框架,所以当时看了很多DDD方面的书,例如领域驱动模式与实战,领域驱动设计:软件核心复杂性 ...

  6. [转]Using Entity Framework (EF) Code-First Migrations in nopCommerce for Fast Customizations

    本文转自:https://www.pronopcommerce.com/using-entity-framework-ef-code-first-migrations-in-nopcommerce-f ...

  7. EF CodeFirst 如何通过配置自动创建数据库<当模型改变时>

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精    本篇为进阶篇,也是弥补自己之前没搞明白的地方,惭愧 ...

  8. EF CodeFirst增删改查之‘CRUD’

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精    本篇旨在学习EF增删改查四大操作 上一节讲述了EF ...

  9. 新年奉献MVC+EF(CodeFirst)+Easyui医药MIS系统

    本人闲来无事就把以前用Asp.net做过的一个医药管理信息系统用mvc,ef ,easyui重新做了一下,业务逻辑简化了许多,旨在加深对mvc,ef(codefirst),easyui,AutoMap ...

随机推荐

  1. asp.net下载的方法

    public void DownLoad( ){ string filePath = Server.MapPath( @"\UserFile\" );//这里注意了,你得指明要下载 ...

  2. iOS之定位与地图

    概览 现在很多社交.电商.团购应用都引入了地图和定位功能,似乎地图功能不再是地图应用 和导航应用所特有的.的确,有了地图和定位功能确实让我们的生活更加丰富多彩,极大的改变了我们的生活方式.例如你到了一 ...

  3. [Form Builder]APP_ITEM_PROPERTY.SET_PROPERTY 用法

    ORACLE 推荐使用此种方法来控制ITEM属性,虽然实质也是调用set_item_instance_property和set_item_property ALTERABLE app_item_pro ...

  4. SQL Server 2008 Values 新用途

    SQL Server 2008中新增功能:可以使用单个Insert命令插入多行. Create table Demo_Values (PKID int not null identity(1,1) p ...

  5. 简单JavaSE数据类型入门

    新的一节学习了JavaSE,今天主要来说一下Java的数据类型及其输出,借用Xmind,可以生动形象的向大家来解释Java的数据类型: 其中数值整数型举例: public class A02{ pub ...

  6. 解决 cocoapods diff: /../Podfile.lock: No such file or directory 问题

    解决cocoapods diff: /../Podfile.lock: No such file or directory google一圈之后,找到两个解决方案: 方案一:
 关闭Xcode,重新执 ...

  7. 【转】 iOS 学习之 NSPredicate 模糊、精确、查询

    简述:Cocoa框架中的NSPredicate用于查询,原理和用法都类似于SQL中的where,作用相当于数据库的过滤取. 定义(最常用到的方法): NSPredicate *ca = [NSPred ...

  8. javascript 基础3第13节

    <html> <head> <title>javascript基础</title> </head> <body> 1.流程控制 ...

  9. Hdu 4514 湫湫系列故事——设计风景线

    湫湫系列故事--设计风景线 Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Total ...

  10. 九度OJ 1437 To Fill or Not to Fill -- 贪心算法

    题目地址:http://ac.jobdu.com/problem.php?pid=1437 题目描述: With highways available, driving a car from Hang ...