系列目录

前言:这是对本文系统一次重要的革新,很久就想要重构数据访问层了,数据访问层重复代码太多。主要集中增删该查每个模块都有,所以本次是为封装相同接口方法

   如果你想了解怎么重构普通的接口DAL层请查看第二节点

   如果你只想了解利用T4链接EF生成代码,可以忽略前两节,之后跳后最后T4模版的使用。

  (代码在最后)

   补充:

  最后必须让初学者理解一个知识点:分部类 partial 关键字,因为我们的重构是围绕分部类而实现,包括接口

partial 关键字指示可在命名空间中定义该类、结构或接口的其他部分。所有部分都必须使用 partial 关键字。在编译时,各个部分都必须可用来形成最终的类型。各个部分必须具有相同的可访问性,如 publicprivate 等。

如果将任意部分声明为抽象的,则整个类型都被视为抽象的。如果将任意部分声明为密封的,则整个类型都被视为密封的。如果任意部分声明基类型,则整个类型都将继承该类。

指定基类的所有部分必须一致,但忽略基类的部分仍继承该基类型。各个部分可以指定不同的基接口,最终类型将实现所有分部声明所列出的全部接口。在某一分部定义中声明的任何类、结构或接口成员可供所有其他部分使用。最终类型是所有部分在编译时的组合。

下列声明:

  1. partial class Earth : Planet, IRotate { }
  2. partial class Earth : IRevolve { }

等效于下列声明:

  1. class Earth : Planet, IRotate, IRevolve { }

知识点:

  1. 改变EF代码生成策略
    1. 改变生成策略为T4
    2. 添加TT模版
  2. 重构DAL层
    1. 创建ICommonRepository<T>接口
    2. 实现ICommonRepository<T>方法
  3. T4模版的使用

1.改变EF代码生成策略旧的ObjectContext改为T4(如果你的项目已经是DBContext API模式请跳过)(操作前备份项目)

在此之前我们也该改变一下代码生成策略,为什么会这个改变。这个项目我最初开始创建的时候用的EF版本为EF4.0当时EF4.0只提供了ObjectContext API接口模式

这个访问方式只能对于DataBase Frist用,不能用于Code Frist.所以一直用到这里,这个并不是很重要,最终都不会影响我们的功能开发

但是DBContext API的亮点,和现在教材都是基于DBContext策略的方式(EF4.1版本之后),我们有必要与时俱进。

操作方式很简单:

第一步:

从旧的ObjectContext改为T4(操作前备份项目)

第二步:

第三步:

->

最后看到DB.emdx下生成了很多模型类。根据表而生成的!这时代码编译将出错,根据出错的类库添加NUGET包。EntityFramework6.1.3版本,添加完之后还会继续报错。

因为ObjectContext有些方法和属性在DBContext已经不能用了

ObjectContext和ObjectSet都提供了AddObject的功能:

比如 context.AddObject("Students", newStudent):

context.Students.AddObject(newStudent):

而 DBContext中则只有DBSet有这个功能,并且名称为成了Add

context.Students.Add(newStudent):

也包括DeleteObject,ObjectStateManager等。

(忽略所有错误。这些错误将在我们重构DAL层被解决)

2.重构DAL层,下面我们来看一张图

图中绿色部分为本次重构部分,再利用成T4连接EF 生成通用分部类部分。这样我们下次不用手动创建继承类,只需要创建其他操作的分部类,很是简单。来看代码才明白

在第一节下载17讲代码

我们来看现有代码,以SysSample 模块的IDAL和DAL为例子

  1. using Apps.Models;
  2. using System.Linq;
  3. namespace Apps.IDAL
  4. {
  5. public interface ISysSampleRepository
  6. {
  7. IQueryable<SysSample> GetList(DBContainer db);
  8. int Create(SysSample entity);
  9. int Delete(string id);
  10. void Delete(DBContainer db, string[] deleteCollection);
  11. /// <param name="entity">实体</param>
  12. int Edit(SysSample entity);
  13. SysSample GetById(string id);
  14. bool IsExist(string id);
  15. }
  16. }
  1. using System;
  2. using System.Linq;
  3. using Apps.IDAL;
  4. using Apps.Models;
  5. using System.Data;
  6.  
  7. namespace Apps.DAL
  8. {
  9. public class SysSampleRepository : ISysSampleRepository, IDisposable
  10. {
  11. public IQueryable<SysSample> GetList(DBContainer db)
  12. {
  13. IQueryable<SysSample> list = db.SysSample.AsQueryable();
  14. return list;
  15. }
  16. public int Create(SysSample entity)
  17. {
  18. using (DBContainer db = new DBContainer())
  19. {
  20. db.SysSample.AddObject(entity);
  21. return db.SaveChanges();
  22. }
  23. }
  24. public int Delete(string id)
  25. {
  26. using (DBContainer db = new DBContainer())
  27. {
  28. SysSample entity = db.SysSample.SingleOrDefault(a => a.Id == id);
  29. if (entity != null)
  30. {
  31.  
  32. db.SysSample.DeleteObject(entity);
  33. }
  34. return db.SaveChanges();
  35. }
  36. }
  37. public int Delete(DBContainer db, string[] deleteCollection)
  38. {
  39. IQueryable<SysSample> collection = from f in db.SysSample
  40. where deleteCollection.Contains(f.Id)
  41. select f;
  42. foreach (var deleteItem in collection)
  43. {
  44. db.SysSample.DeleteObject(deleteItem);
  45. }
  46. }
  47. public int Edit(SysSample entity)
  48. {
  49. using (DBContainer db = new DBContainer())
  50. {
  51. db.SysSample.Attach(entity);
  52. db.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
  53. return db.SaveChanges();
  54. }
  55. }
  56. public SysSample GetById(string id)
  57. {
  58. using (DBContainer db = new DBContainer())
  59. {
  60. return db.SysSample.SingleOrDefault(a => a.Id == id);
  61. }
  62. }
  63. public bool IsExist(string id)
  64. {
  65. using (DBContainer db = new DBContainer())
  66. {
  67. SysSample entity = GetById(id);
  68. if (entity != null)
  69. return true;
  70. return false;
  71. }
  72. }
  73. public void Dispose()
  74. {
  75.  
  76. }
  77. }
  78. }

看到我们其他模块也都必须实现类似代码。其中不同之处只有SysSample模型

好在.net提供索引访问对象的强类型List<T>这里的T代表SysSamle。是可变的

1.接下来我们实现通用接口在IDAL层

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7.  
  8. namespace Apps.IDAL
  9. {
  10. public interface ICommonRepository<T> where T :class
  11. {
  12. bool Create(T model);
  13. bool Edit(T model);
  14. bool Delete(T model);
  15. /// <summary>
  16. /// 按主键删除
  17. /// </summary>
  18. /// <param name="keyValues"></param>
  19. int Delete(params object[] keyValues);
  20. T GetById(params object[] keyValues);
  21. /// <summary>
  22. /// 获得所有数据
  23. /// </summary>
  24. /// <returns></returns>
  25. IQueryable<T> GetList();
  26. /// <summary>
  27. /// 根据表达式获取数据
  28. /// </summary>
  29. /// <param name="whereLambda"></param>
  30. /// <returns></returns>
  31. IQueryable<T> GetList(Func<T, bool> whereLambda);bool IsExist(string id);
  32. int SaveChanges();
  33. }
  34. }

代码解析:接口实现了增删改查通用接口,并声明 where T :class 【T必须是一个类(class)类型】

2.接下来我们实现通用方法DAL层 按照重构图所示,应该继承ICommonRepository接口,并实现接口方法

  1. using Apps.IDAL;
  2. using Apps.Models;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Data.Entity;
  6. using System.Linq;
  7. using System.Linq.Expressions;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10.  
  11. namespace Apps.DAL
  12. {
  13. public abstract class CommonRepository<T> : ICommonRepository<T> where T:class
  14. {
  15. DBContainer db;
  16. public CommonRepository(DBContainer context)
  17. {
  18. this.db = context;
  19. }
  20.  
  21. public DBContainer Context
  22. {
  23. get { return db; }
  24. }
  25.  
  26. public virtual bool Create(T model)
  27. {
  28. db.Set<T>().Add(model);
  29. return db.SaveChanges()>;
  30. }
  31.  
  32. public virtual bool Edit(T model)
  33. {
  34. if (db.Entry<T>(model).State == EntityState.Modified)
  35. {
  36. return db.SaveChanges() > ;
  37. }
  38. else if (db.Entry<T>(model).State == EntityState.Detached)
  39. {
  40. try
  41. {
  42. db.Set<T>().Attach(model);
  43. db.Entry<T>(model).State = EntityState.Modified;
  44. }
  45. catch (InvalidOperationException)
  46. {
  47. //T old = Find(model._ID);
  48. //db.Entry<old>.CurrentValues.SetValues(model);
  49. }
  50. return db.SaveChanges()>;
  51. }
  52. return false;
  53. }
  54.  
  55. public virtual bool Delete(T model)
  56. {
  57. db.Set<T>().Remove(model);
  58. return db.SaveChanges()>;
  59. }
  60.  
  61. public virtual int Delete(params object[] keyValues)
  62. {
  63. T model = GetById(keyValues);
  64. if(model!=null)
  65. {
  66. db.Set<T>().Remove(model);
  67. return db.SaveChanges();
  68. }
  69. return -;
  70. }
  71. public virtual T GetById(params object[] keyValues)
  72. {
  73. return db.Set<T>().Find(keyValues);
  74. }
  75.  
  76. public virtual IQueryable<T> GetList()
  77. {
  78. return db.Set<T>();
  79. }
  80.  
  81. public virtual IQueryable<T> GetList(Func<T, bool> whereLambda)
  82. {
  83. return db.Set<T>().Where(whereLambda).AsQueryable();
  84. }
  85. public virtual bool IsExist(string id)
  86. {
  87. return GetById(id)!=null;
  88. }
  89.  
  90. public int SaveChanges()
  91. {
  92. return db.SaveChanges();
  93. }
  94. }
  95. }

OK.全是DBContext API 操作EF方法。增删改查

3.T4生成分部类

接下来我们来看这么用这个接口

我们IDAL所有表(即模块)都要实现ICommonRepository接口好调用其中的增删改查做扩展

删掉ISysSampleRepository中的原来代码变为:

  1. using Apps.Models;
  2. using System.Linq;
  3. namespace Apps.IDAL
  4. {
  5. public interface ISysSampleRepository : ICommonRepository<SysSample>
  6. {
  7.  
  8. }
  9. }

观察到这里也是重复代码,因为同理我们所有表都要实现这样的接口,这样我们可以利用T4来生成这种的重复代码

我以前写过一篇文章是关于T4链接数据库的。构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(29)-T4模版

这里我们是直接链接edmx的。同理

1.新建一个文件夹。如下图所示并创建一个TT模版

创建后会产生2个文件。删掉Context.tt,因为在Apps.Models已经有了

配置第五行的inputFile为上面所描述,可能因为环境不同你们EF路径有所不同。保存后TT模版会自动生成

tt模版如果没有高亮显示的。要安装一些工具。因为我是一边改一边发文章的。我这里也是没有的,下载T4Editor 安装高亮,什么版本就下什么就可以了(或者通过VS工具------扩展与更新 搜索)

http://t4-editor.tangible-engineering.com/Download_T4Editor_Plus_ModelingTools.html

tangible T4 Editor 2.3.0 plus modeling tools for Visual Studio 2015Download from Visual Studio Gallery

tangible T4 Editor 2.3.0 plus modeling tools for Visual Studio 2013Download from Visual Studio Gallery

按照ISysSampleRepository接口为例子。修改TT模版后代码

  1. <#@ template language="C#" debug="false" hostspecific="true"#>
  2. <#@ include file="EF6.Utility.CS.ttinclude"#><#@
  3. output extension=".cs"#><#
  4.  
  5. const string inputFile = @"../../Apps.Models/DB.edmx";
  6. var textTransform = DynamicTextTransformation.Create(this);
  7. var code = new CodeGenerationTools(this);
  8. var ef = new MetadataTools(this);
  9. var typeMapper = new TypeMapper(code, ef, textTransform.Errors);
  10. var fileManager = EntityFrameworkTemplateFileManager.Create(this);
  11. var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile);
  12. var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef);
  13.  
  14. if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile))
  15. {
  16. return string.Empty;
  17. }
  18.  
  19. WriteHeader(codeStringGenerator, fileManager);
  20.  
  21. foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection))
  22. {
  23. fileManager.StartNewFile("I"+entity.Name + "Repository.cs");
  24. #>
  25. using Apps.Models;
  26. namespace Apps.IDAL
  27. {
  28. public partial interface I<#=entity.Name #>Repository:ICommonRepository<<#=entity.Name #>>
  29. {
  30.  
  31. }
  32. <#
  33. EndNamespace(code);
  34. }
  35.  
  36. fileManager.Process();
  37.  
  38. #>
  39. <#+
  40.  
  41. public void WriteHeader(CodeStringGenerator codeStringGenerator, EntityFrameworkTemplateFileManager fileManager)
  42. {
  43. fileManager.StartHeader();
  44. #>
  45. //------------------------------------------------------------------------------
  46. // <auto-generated>
  47. // <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine1")#>
  48. //
  49. // <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine2")#>
  50. // <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine3")#>
  51. // </auto-generated>
  52. //------------------------------------------------------------------------------
  53. <#=codeStringGenerator.UsingDirectives(inHeader: true)#>
  54. <#+
  55. fileManager.EndBlock();
  56. }
  57.  
  58. public void BeginNamespace(CodeGenerationTools code)
  59. {
  60. var codeNamespace = code.VsNamespaceSuggestion();
  61. if (!String.IsNullOrEmpty(codeNamespace))
  62. {
  63. #>
  64. namespace <#=code.EscapeNamespace(codeNamespace)#>
  65. {
  66. <#+
  67. PushIndent(" ");
  68. }
  69. }
  70.  
  71. public void EndNamespace(CodeGenerationTools code)
  72. {
  73. if (!String.IsNullOrEmpty(code.VsNamespaceSuggestion()))
  74. {
  75. PopIndent();
  76. #>
  77. }
  78. <#+
  79. }
  80. }
  81.  
  82. public const string TemplateId = "CSharp_DbContext_Types_EF6";
  83.  
  84. public class CodeStringGenerator
  85. {
  86. private readonly CodeGenerationTools _code;
  87. private readonly TypeMapper _typeMapper;
  88. private readonly MetadataTools _ef;
  89.  
  90. public CodeStringGenerator(CodeGenerationTools code, TypeMapper typeMapper, MetadataTools ef)
  91. {
  92. ArgumentNotNull(code, "code");
  93. ArgumentNotNull(typeMapper, "typeMapper");
  94. ArgumentNotNull(ef, "ef");
  95.  
  96. _code = code;
  97. _typeMapper = typeMapper;
  98. _ef = ef;
  99. }
  100.  
  101. public string Property(EdmProperty edmProperty)
  102. {
  103. return string.Format(
  104. CultureInfo.InvariantCulture,
  105. "{0} {1} {2} {{ {3}get; {4}set; }}",
  106. Accessibility.ForProperty(edmProperty),
  107. _typeMapper.GetTypeName(edmProperty.TypeUsage),
  108. _code.Escape(edmProperty),
  109. _code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
  110. _code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
  111. }
  112.  
  113. public string NavigationProperty(NavigationProperty navProp)
  114. {
  115. var endType = _typeMapper.GetTypeName(navProp.ToEndMember.GetEntityType());
  116. return string.Format(
  117. CultureInfo.InvariantCulture,
  118. "{0} {1} {2} {{ {3}get; {4}set; }}",
  119. AccessibilityAndVirtual(Accessibility.ForNavigationProperty(navProp)),
  120. navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,
  121. _code.Escape(navProp),
  122. _code.SpaceAfter(Accessibility.ForGetter(navProp)),
  123. _code.SpaceAfter(Accessibility.ForSetter(navProp)));
  124. }
  125.  
  126. public string AccessibilityAndVirtual(string accessibility)
  127. {
  128. return accessibility + (accessibility != "private" ? " virtual" : "");
  129. }
  130.  
  131. public string EntityClassOpening(EntityType entity)
  132. {
  133. return string.Format(
  134. CultureInfo.InvariantCulture,
  135. "{0} {1}partial class {2}{3}",
  136. Accessibility.ForType(entity),
  137. _code.SpaceAfter(_code.AbstractOption(entity)),
  138. _code.Escape(entity),
  139. _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)));
  140. }
  141.  
  142. public string EnumOpening(SimpleType enumType)
  143. {
  144. return string.Format(
  145. CultureInfo.InvariantCulture,
  146. "{0} enum {1} : {2}",
  147. Accessibility.ForType(enumType),
  148. _code.Escape(enumType),
  149. _code.Escape(_typeMapper.UnderlyingClrType(enumType)));
  150. }
  151.  
  152. public void WriteFunctionParameters(EdmFunction edmFunction, Action<string, string, string, string> writeParameter)
  153. {
  154. var parameters = FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef);
  155. foreach (var parameter in parameters.Where(p => p.NeedsLocalVariable))
  156. {
  157. var isNotNull = parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null";
  158. var notNullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", " + parameter.FunctionParameterName + ")";
  159. var nullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", typeof(" + TypeMapper.FixNamespaces(parameter.RawClrTypeName) + "))";
  160. writeParameter(parameter.LocalVariableName, isNotNull, notNullInit, nullInit);
  161. }
  162. }
  163.  
  164. public string ComposableFunctionMethod(EdmFunction edmFunction, string modelNamespace)
  165. {
  166. var parameters = _typeMapper.GetParameters(edmFunction);
  167.  
  168. return string.Format(
  169. CultureInfo.InvariantCulture,
  170. "{0} IQueryable<{1}> {2}({3})",
  171. AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)),
  172. _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace),
  173. _code.Escape(edmFunction),
  174. string.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray()));
  175. }
  176.  
  177. public string ComposableCreateQuery(EdmFunction edmFunction, string modelNamespace)
  178. {
  179. var parameters = _typeMapper.GetParameters(edmFunction);
  180.  
  181. return string.Format(
  182. CultureInfo.InvariantCulture,
  183. "return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<{0}>(\"[{1}].[{2}]({3})\"{4});",
  184. _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace),
  185. edmFunction.NamespaceName,
  186. edmFunction.Name,
  187. string.Join(", ", parameters.Select(p => "@" + p.EsqlParameterName).ToArray()),
  188. _code.StringBefore(", ", string.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray())));
  189. }
  190.  
  191. public string FunctionMethod(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption)
  192. {
  193. var parameters = _typeMapper.GetParameters(edmFunction);
  194. var returnType = _typeMapper.GetReturnType(edmFunction);
  195.  
  196. var paramList = String.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray());
  197. if (includeMergeOption)
  198. {
  199. paramList = _code.StringAfter(paramList, ", ") + "MergeOption mergeOption";
  200. }
  201.  
  202. return string.Format(
  203. CultureInfo.InvariantCulture,
  204. "{0} {1} {2}({3})",
  205. AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)),
  206. returnType == null ? "int" : "ObjectResult<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">",
  207. _code.Escape(edmFunction),
  208. paramList);
  209. }
  210.  
  211. public string ExecuteFunction(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption)
  212. {
  213. var parameters = _typeMapper.GetParameters(edmFunction);
  214. var returnType = _typeMapper.GetReturnType(edmFunction);
  215.  
  216. var callParams = _code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()));
  217. if (includeMergeOption)
  218. {
  219. callParams = ", mergeOption" + callParams;
  220. }
  221.  
  222. return string.Format(
  223. CultureInfo.InvariantCulture,
  224. "return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction{0}(\"{1}\"{2});",
  225. returnType == null ? "" : "<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">",
  226. edmFunction.Name,
  227. callParams);
  228. }
  229.  
  230. public string DbSet(EntitySet entitySet)
  231. {
  232. return string.Format(
  233. CultureInfo.InvariantCulture,
  234. "{0} virtual DbSet<{1}> {2} {{ get; set; }}",
  235. Accessibility.ForReadOnlyProperty(entitySet),
  236. _typeMapper.GetTypeName(entitySet.ElementType),
  237. _code.Escape(entitySet));
  238. }
  239.  
  240. public string UsingDirectives(bool inHeader, bool includeCollections = true)
  241. {
  242. return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion())
  243. ? string.Format(
  244. CultureInfo.InvariantCulture,
  245. "{0}using System;{1}" +
  246. "{2}",
  247. inHeader ? Environment.NewLine : "",
  248. includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "",
  249. inHeader ? "" : Environment.NewLine)
  250. : "";
  251. }
  252. }
  253.  
  254. public class TypeMapper
  255. {
  256. private const string ExternalTypeNameAttributeName = @"http://schemas.microsoft.com/ado/2006/04/codegeneration:ExternalTypeName";
  257.  
  258. private readonly System.Collections.IList _errors;
  259. private readonly CodeGenerationTools _code;
  260. private readonly MetadataTools _ef;
  261.  
  262. public TypeMapper(CodeGenerationTools code, MetadataTools ef, System.Collections.IList errors)
  263. {
  264. ArgumentNotNull(code, "code");
  265. ArgumentNotNull(ef, "ef");
  266. ArgumentNotNull(errors, "errors");
  267.  
  268. _code = code;
  269. _ef = ef;
  270. _errors = errors;
  271. }
  272.  
  273. public static string FixNamespaces(string typeName)
  274. {
  275. return typeName.Replace("System.Data.Spatial.", "System.Data.Entity.Spatial.");
  276. }
  277.  
  278. public string GetTypeName(TypeUsage typeUsage)
  279. {
  280. return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace: null);
  281. }
  282.  
  283. public string GetTypeName(EdmType edmType)
  284. {
  285. return GetTypeName(edmType, isNullable: null, modelNamespace: null);
  286. }
  287.  
  288. public string GetTypeName(TypeUsage typeUsage, string modelNamespace)
  289. {
  290. return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace);
  291. }
  292.  
  293. public string GetTypeName(EdmType edmType, string modelNamespace)
  294. {
  295. return GetTypeName(edmType, isNullable: null, modelNamespace: modelNamespace);
  296. }
  297.  
  298. public string GetTypeName(EdmType edmType, bool? isNullable, string modelNamespace)
  299. {
  300. if (edmType == null)
  301. {
  302. return null;
  303. }
  304.  
  305. var collectionType = edmType as CollectionType;
  306. if (collectionType != null)
  307. {
  308. return String.Format(CultureInfo.InvariantCulture, "ICollection<{0}>", GetTypeName(collectionType.TypeUsage, modelNamespace));
  309. }
  310.  
  311. var typeName = _code.Escape(edmType.MetadataProperties
  312. .Where(p => p.Name == ExternalTypeNameAttributeName)
  313. .Select(p => (string)p.Value)
  314. .FirstOrDefault())
  315. ?? (modelNamespace != null && edmType.NamespaceName != modelNamespace ?
  316. _code.CreateFullName(_code.EscapeNamespace(edmType.NamespaceName), _code.Escape(edmType)) :
  317. _code.Escape(edmType));
  318.  
  319. if (edmType is StructuralType)
  320. {
  321. return typeName;
  322. }
  323.  
  324. if (edmType is SimpleType)
  325. {
  326. var clrType = UnderlyingClrType(edmType);
  327. if (!IsEnumType(edmType))
  328. {
  329. typeName = _code.Escape(clrType);
  330. }
  331.  
  332. typeName = FixNamespaces(typeName);
  333.  
  334. return clrType.IsValueType && isNullable == true ?
  335. String.Format(CultureInfo.InvariantCulture, "Nullable<{0}>", typeName) :
  336. typeName;
  337. }
  338.  
  339. throw new ArgumentException("edmType");
  340. }
  341.  
  342. public Type UnderlyingClrType(EdmType edmType)
  343. {
  344. ArgumentNotNull(edmType, "edmType");
  345.  
  346. var primitiveType = edmType as PrimitiveType;
  347. if (primitiveType != null)
  348. {
  349. return primitiveType.ClrEquivalentType;
  350. }
  351.  
  352. if (IsEnumType(edmType))
  353. {
  354. return GetEnumUnderlyingType(edmType).ClrEquivalentType;
  355. }
  356.  
  357. return typeof(object);
  358. }
  359.  
  360. public object GetEnumMemberValue(MetadataItem enumMember)
  361. {
  362. ArgumentNotNull(enumMember, "enumMember");
  363.  
  364. var valueProperty = enumMember.GetType().GetProperty("Value");
  365. return valueProperty == null ? null : valueProperty.GetValue(enumMember, null);
  366. }
  367.  
  368. public string GetEnumMemberName(MetadataItem enumMember)
  369. {
  370. ArgumentNotNull(enumMember, "enumMember");
  371.  
  372. var nameProperty = enumMember.GetType().GetProperty("Name");
  373. return nameProperty == null ? null : (string)nameProperty.GetValue(enumMember, null);
  374. }
  375.  
  376. public System.Collections.IEnumerable GetEnumMembers(EdmType enumType)
  377. {
  378. ArgumentNotNull(enumType, "enumType");
  379.  
  380. var membersProperty = enumType.GetType().GetProperty("Members");
  381. return membersProperty != null
  382. ? (System.Collections.IEnumerable)membersProperty.GetValue(enumType, null)
  383. : Enumerable.Empty<MetadataItem>();
  384. }
  385.  
  386. public bool EnumIsFlags(EdmType enumType)
  387. {
  388. ArgumentNotNull(enumType, "enumType");
  389.  
  390. var isFlagsProperty = enumType.GetType().GetProperty("IsFlags");
  391. return isFlagsProperty != null && (bool)isFlagsProperty.GetValue(enumType, null);
  392. }
  393.  
  394. public bool IsEnumType(GlobalItem edmType)
  395. {
  396. ArgumentNotNull(edmType, "edmType");
  397.  
  398. return edmType.GetType().Name == "EnumType";
  399. }
  400.  
  401. public PrimitiveType GetEnumUnderlyingType(EdmType enumType)
  402. {
  403. ArgumentNotNull(enumType, "enumType");
  404.  
  405. return (PrimitiveType)enumType.GetType().GetProperty("UnderlyingType").GetValue(enumType, null);
  406. }
  407.  
  408. public string CreateLiteral(object value)
  409. {
  410. if (value == null || value.GetType() != typeof(TimeSpan))
  411. {
  412. return _code.CreateLiteral(value);
  413. }
  414.  
  415. return string.Format(CultureInfo.InvariantCulture, "new TimeSpan({0})", ((TimeSpan)value).Ticks);
  416. }
  417.  
  418. public bool VerifyCaseInsensitiveTypeUniqueness(IEnumerable<string> types, string sourceFile)
  419. {
  420. ArgumentNotNull(types, "types");
  421. ArgumentNotNull(sourceFile, "sourceFile");
  422.  
  423. var hash = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
  424. if (types.Any(item => !hash.Add(item)))
  425. {
  426. _errors.Add(
  427. new CompilerError(sourceFile, -, -, "",
  428. String.Format(CultureInfo.CurrentCulture, CodeGenerationTools.GetResourceString("Template_CaseInsensitiveTypeConflict"))));
  429. return false;
  430. }
  431. return true;
  432. }
  433.  
  434. public IEnumerable<SimpleType> GetEnumItemsToGenerate(IEnumerable<GlobalItem> itemCollection)
  435. {
  436. return GetItemsToGenerate<SimpleType>(itemCollection)
  437. .Where(e => IsEnumType(e));
  438. }
  439.  
  440. public IEnumerable<T> GetItemsToGenerate<T>(IEnumerable<GlobalItem> itemCollection) where T: EdmType
  441. {
  442. return itemCollection
  443. .OfType<T>()
  444. .Where(i => !i.MetadataProperties.Any(p => p.Name == ExternalTypeNameAttributeName))
  445. .OrderBy(i => i.Name);
  446. }
  447.  
  448. public IEnumerable<string> GetAllGlobalItems(IEnumerable<GlobalItem> itemCollection)
  449. {
  450. return itemCollection
  451. .Where(i => i is EntityType || i is ComplexType || i is EntityContainer || IsEnumType(i))
  452. .Select(g => GetGlobalItemName(g));
  453. }
  454.  
  455. public string GetGlobalItemName(GlobalItem item)
  456. {
  457. if (item is EdmType)
  458. {
  459. return ((EdmType)item).Name;
  460. }
  461. else
  462. {
  463. return ((EntityContainer)item).Name;
  464. }
  465. }
  466.  
  467. public IEnumerable<EdmProperty> GetSimpleProperties(EntityType type)
  468. {
  469. return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type);
  470. }
  471.  
  472. public IEnumerable<EdmProperty> GetSimpleProperties(ComplexType type)
  473. {
  474. return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type);
  475. }
  476.  
  477. public IEnumerable<EdmProperty> GetComplexProperties(EntityType type)
  478. {
  479. return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type);
  480. }
  481.  
  482. public IEnumerable<EdmProperty> GetComplexProperties(ComplexType type)
  483. {
  484. return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type);
  485. }
  486.  
  487. public IEnumerable<EdmProperty> GetPropertiesWithDefaultValues(EntityType type)
  488. {
  489. return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null);
  490. }
  491.  
  492. public IEnumerable<EdmProperty> GetPropertiesWithDefaultValues(ComplexType type)
  493. {
  494. return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null);
  495. }
  496.  
  497. public IEnumerable<NavigationProperty> GetNavigationProperties(EntityType type)
  498. {
  499. return type.NavigationProperties.Where(np => np.DeclaringType == type);
  500. }
  501.  
  502. public IEnumerable<NavigationProperty> GetCollectionNavigationProperties(EntityType type)
  503. {
  504. return type.NavigationProperties.Where(np => np.DeclaringType == type && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);
  505. }
  506.  
  507. public FunctionParameter GetReturnParameter(EdmFunction edmFunction)
  508. {
  509. ArgumentNotNull(edmFunction, "edmFunction");
  510.  
  511. var returnParamsProperty = edmFunction.GetType().GetProperty("ReturnParameters");
  512. return returnParamsProperty == null
  513. ? edmFunction.ReturnParameter
  514. : ((IEnumerable<FunctionParameter>)returnParamsProperty.GetValue(edmFunction, null)).FirstOrDefault();
  515. }
  516.  
  517. public bool IsComposable(EdmFunction edmFunction)
  518. {
  519. ArgumentNotNull(edmFunction, "edmFunction");
  520.  
  521. var isComposableProperty = edmFunction.GetType().GetProperty("IsComposableAttribute");
  522. return isComposableProperty != null && (bool)isComposableProperty.GetValue(edmFunction, null);
  523. }
  524.  
  525. public IEnumerable<FunctionImportParameter> GetParameters(EdmFunction edmFunction)
  526. {
  527. return FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef);
  528. }
  529.  
  530. public TypeUsage GetReturnType(EdmFunction edmFunction)
  531. {
  532. var returnParam = GetReturnParameter(edmFunction);
  533. return returnParam == null ? null : _ef.GetElementType(returnParam.TypeUsage);
  534. }
  535.  
  536. public bool GenerateMergeOptionFunction(EdmFunction edmFunction, bool includeMergeOption)
  537. {
  538. var returnType = GetReturnType(edmFunction);
  539. return !includeMergeOption && returnType != null && returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType;
  540. }
  541. }
  542.  
  543. public static void ArgumentNotNull<T>(T arg, string name) where T : class
  544. {
  545. if (arg == null)
  546. {
  547. throw new ArgumentNullException(name);
  548. }
  549. }
  550. #>

ICommonRepository

核心代码解析:

  1. foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection))
  2. {
  3. fileManager.StartNewFile("I"+entity.Name + "Repository.cs");
  4. #>
  5. using Apps.Models;
  6. namespace Apps.IDAL
  7. {
  8. public partial interface I<#=entity.Name #>Repository:ICommonRepository<<#=entity.Name #>>
  9. {
  10.  
  11. }
  12. <#
  13. EndNamespace(code);
  14. }
  15.  
  16. fileManager.Process();
  17.  
  18. #>

循环生成。达到预期效果

TT模版里面太多代码很难看懂,需要看官方帮助文档才行。但是我们可以提取公共部分。以后写TT就引入。看图

在WriteHeder方法后都是通用的访问代码。我们提取之后的代码。因为安装了T4高亮。我只能调浅色,深色效果太差

在Apps.Models创建 Common.ttinclude来做公共部分(你可以创建在其他路径,到时候是引入路径为准)

最后修改:ICommonRepository.tt第二行代码:

  1. <#@ include file="../../Apps.Models/Common.ttinclude"#><#@

OK。看起来间接很多了,以后创建其他tt文件就可以直接引用公共部分,如果不提取tt模版也是没有问题的。

同理我们创建DAL层的公共部分,生成后的代码如下,同样是一个分部类CommonRepository

  1. <#@ template language="C#" debug="false" hostspecific="true"#>
  2. <#@ include file="../../Apps.Models/Common.ttinclude"#><#@
  3. output extension=".cs"#>
  4. <#
  5.  
  6. const string inputFile = @"../../Apps.Models/DB.edmx";
  7. var textTransform = DynamicTextTransformation.Create(this);
  8. var code = new CodeGenerationTools(this);
  9. var ef = new MetadataTools(this);
  10. var typeMapper = new TypeMapper(code, ef, textTransform.Errors);
  11. var fileManager = EntityFrameworkTemplateFileManager.Create(this);
  12. var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile);
  13. var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef);
  14.  
  15. if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile))
  16. {
  17. return string.Empty;
  18. }
  19.  
  20. WriteHeader(codeStringGenerator, fileManager);
  21.  
  22. foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection))
  23. {
  24. fileManager.StartNewFile("I"+entity.Name + "Repository.cs");
  25. #>
  26. using Apps.Models;
  27. using Apps.DAL;
  28. namespace Apps.IDAL
  29. {
  30. public partial class <#=entity.Name #>Repository:CommonRepository<<#=entity.Name #>>
  31. {
  32. public <#=entity.Name #>Repository(DBContainer db):base(db)
  33. {
  34.  
  35. }
  36. }
  37. <#
  38. EndNamespace(code);
  39. }
  40.  
  41. fileManager.Process();
  42.  
  43. #>

CommonRepository.tt

  1. //------------------------------------------------------------------------------
  2. // <auto-generated>
  3. // 此代码已从模板生成。
  4. //
  5. // 手动更改此文件可能导致应用程序出现意外的行为。
  6. // 如果重新生成代码,将覆盖对此文件的手动更改。
  7. // </auto-generated>
  8. //------------------------------------------------------------------------------
  9.  
  10. using Apps.Models;
  11. using Apps.DAL;
  12. namespace Apps.IDAL
  13. {
  14. public partial class SysSampleRepository:CommonRepository<SysSample>
  15. {
  16. public SysSampleRepository(DBContainer db):base(db)
  17. {
  18.  
  19. }
  20. }
  21. }

接下来原来很长的ISysSampleRepository接口最后变成了一个分部接口

  1. using Apps.Models;
  2. using System.Linq;
  3. namespace Apps.IDAL
  4. {
  5. public partial interface ISysSampleRepository
  6. {
  7.   //处理通用部分外的业务
  8. }
  9. }

SysSampleRepository变成了一个分部类

  1. using System;
  2. using System.Linq;
  3. using Apps.IDAL;
  4. using Apps.Models;
  5. using System.Data;
  6.  
  7. namespace Apps.DAL
  8. {
  9. public class SysSampleRepository
  10. {
  1.     //处理通用部分外的业务
  1. } }
  1.  

可以处理通用部分外的业务

这样我们关注点真的很专注了。Ye...

关于业务层,肯定还是报错的状态,这时候我们就来修改一下

例如:

变为

最后业务层代码:

  1. //------------------------------------------------------------------------------
  2. // <auto-generated>
  3. // 此代码由T4模板自动生成
  4. // 生成时间 2013-04-22 10:41:47 by App
  5. // 对此文件的更改可能会导致不正确的行为,并且如果
  6. // 重新生成代码,这些更改将会丢失。
  7. // </auto-generated>
  8. //------------------------------------------------------------------------------
  9.  
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. using Microsoft.Practices.Unity;
  14. using Apps.Models;
  15. using Apps.Common;
  16. using System.Transactions;
  17. using Apps.Models.Sys;
  18. using Apps.IBLL;
  19. using Apps.IDAL;
  20. using Apps.BLL.Core;
  21. using Apps.Locale;
  22.  
  23. namespace Apps.BLL
  24. {
  25. public class SysSampleBLL : BaseBLL, ISysSampleBLL
  26. {
  27.  
  28. [Dependency]
  29. public ISysSampleRepository m_Rep { get; set; }
  30.  
  31. public List<SysSampleModel> GetList(ref GridPager pager, string queryStr)
  32. {
  33.  
  34. IQueryable<SysSample> queryData = null;
  35. if (!string.IsNullOrWhiteSpace(queryStr))
  36. {
  37. queryData = m_Rep.GetList(a => a.Name.Contains(queryStr) || a.Note.Contains(queryStr));
  38. }
  39. else
  40. {
  41. queryData = m_Rep.GetList();
  42. }
  43. pager.totalRows = queryData.Count();
  44. //排序
  45. queryData = LinqHelper.SortingAndPaging(queryData, pager.sort, pager.order, pager.page, pager.rows);
  46. return CreateModelList(ref queryData);
  47. }
  48. private List<SysSampleModel> CreateModelList(ref IQueryable<SysSample> queryData)
  49. {
  50.  
  51. List<SysSampleModel> modelList = (from r in queryData
  52. select new SysSampleModel
  53. {
  54. Id = r.Id,
  55. Name = r.Name,
  56. Age = r.Age,
  57. Bir = r.Bir,
  58. Photo = r.Photo,
  59. Note = r.Note,
  60. CreateTime = r.CreateTime,
  61.  
  62. }).ToList();
  63.  
  64. return modelList;
  65. }
  66.  
  67. public bool Create(ref ValidationErrors errors, SysSampleModel model)
  68. {
  69. try
  70. {
  71. SysSample entity = m_Rep.GetById(model.Id);
  72. if (entity != null)
  73. {
  74. errors.Add(Resource.PrimaryRepeat);
  75. return false;
  76. }
  77. entity = new SysSample();
  78. entity.Id = model.Id;
  79. entity.Name = model.Name;
  80. entity.Age = model.Age;
  81. entity.Bir = model.Bir;
  82. entity.Photo = model.Photo;
  83. entity.Note = model.Note;
  84. entity.CreateTime = model.CreateTime;
  85.  
  86. if (m_Rep.Create(entity))
  87. {
  88. return true;
  89. }
  90. else
  91. {
  92. errors.Add(Resource.InsertFail);
  93. return false;
  94. }
  95. }
  96. catch (Exception ex)
  97. {
  98. errors.Add(ex.Message);
  99. ExceptionHander.WriteException(ex);
  100. return false;
  101. }
  102. }
  103.  
  104. public bool Delete(ref ValidationErrors errors, string id)
  105. {
  106. try
  107. {
  108. if (m_Rep.Delete(id) == )
  109. {
  110. return true;
  111. }
  112. else
  113. {
  114. return false;
  115. }
  116. }
  117. catch (Exception ex)
  118. {
  119. errors.Add(ex.Message);
  120. ExceptionHander.WriteException(ex);
  121. return false;
  122. }
  123. }
  124.  
  125. public bool Delete(ref ValidationErrors errors, string[] deleteCollection)
  126. {
  127. try
  128. {
  129. if (deleteCollection != null)
  130. {
  131. using (TransactionScope transactionScope = new TransactionScope())
  132. {
  133.  
  134. m_Rep.Delete(deleteCollection);
  135. if (db.SaveChanges() == deleteCollection.Length)
  136. {
  137. transactionScope.Complete();
  138. return true;
  139. }
  140. else
  141. {
  142. Transaction.Current.Rollback();
  143. return false;
  144. }
  145. }
  146. }
  147. return false;
  148. }
  149. catch (Exception ex)
  150. {
  151. errors.Add(ex.Message);
  152. ExceptionHander.WriteException(ex);
  153. return false;
  154. }
  155. }
  156.  
  157. public bool Edit(ref ValidationErrors errors, SysSampleModel model)
  158. {
  159. try
  160. {
  161. SysSample entity = m_Rep.GetById(model.Id);
  162. if (entity == null)
  163. {
  164. errors.Add(Resource.Disable);
  165. return false;
  166. }
  167. entity.Name = model.Name;
  168. entity.Age = model.Age;
  169. entity.Bir = model.Bir;
  170. entity.Photo = model.Photo;
  171. entity.Note = model.Note;
  172.  
  173. if (m_Rep.Edit(entity))
  174. {
  175. return true;
  176. }
  177. else
  178. {
  179. errors.Add(Resource.EditFail);
  180. return false;
  181. }
  182.  
  183. }
  184. catch (Exception ex)
  185. {
  186. errors.Add(ex.Message);
  187. ExceptionHander.WriteException(ex);
  188. return false;
  189. }
  190. }
  191.  
  192. public bool IsExists(string id)
  193. {
  194. if (db.SysSample.SingleOrDefault(a => a.Id == id) != null)
  195. {
  196. return true;
  197. }
  198. return false;
  199. }
  200.  
  201. public SysSampleModel GetById(string id)
  202. {
  203. if (IsExist(id))
  204. {
  205. SysSample entity = m_Rep.GetById(id);
  206. SysSampleModel model = new SysSampleModel();
  207. model.Id = entity.Id;
  208. model.Name = entity.Name;
  209. model.Age = entity.Age;
  210. model.Bir = entity.Bir;
  211. model.Photo = entity.Photo;
  212. model.Note = entity.Note;
  213. model.CreateTime = entity.CreateTime;
  214.  
  215. return model;
  216. }
  217. else
  218. {
  219. return null;
  220. }
  221. }
  222.  
  223. public bool IsExist(string id)
  224. {
  225. return m_Rep.IsExist(id);
  226. }
  227. }
  228. }

--------------------------------------------------------------------------------写在最后--------------------------------------------------------------------------------

可以对比以前DAL层的代码,明显的减少很多(虽然业务层没有减少)。也许在以后业务层也有必要的重构!

最后我完全修改了我项目的DAL层。用数据直接说话

整整少了两万行。却完成了相同的功能。(代码类型.cs,与事实可能有点差别,但是可以效果明显)

代码参考下载。重构后的架构(VS2013)执行根目录下的script.sql脚本。并修改web.config数据库链接即可查看

如查看重构前代码可以到第一节下载17节代码

https://yunpan.cn/cYUdjssbmiLrL  提取码 e622

ASP.NET MVC5+EF6+EasyUI 后台管理系统(58)-DAL层重构的更多相关文章

  1. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库  您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB  升级后界面效果如下: 任务调度系统界面 http: ...

  2. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(转)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库 您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB 升级后界面效果如下: 日程管理   http://ww ...

  3. ASP.NET MVC5+EF6+EasyUI 后台管理系统(63)-Excel导入和导出-自定义表模导入

    系列目录 前言 上一节使用了LinqToExcel和CloseXML对Excel表进行导入和导出的简单操作,大家可以跳转到上一节查看: ASP.NET MVC5+EF6+EasyUI 后台管理系统(6 ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统-WebApi的用法与调试

    1:ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-WebApi与Unity注入 使用Unity是为了使用我们后台的BLL和DAL层 2:ASP.NET MVC5+EF6+Easy ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(51)-系统升级

    系统很久没有更新内容了,期待已久的更新在今天发布了,最近花了2个月的时间每天一点点,从原有系统 MVC4+EF5+UNITY2.X+Quartz 2.0+easyui 1.3.4无缝接入 MVC5+E ...

  6. ASP.NET MVC5+EF6+EasyUI 后台管理系统(34)-文章发布系统①-简要分析

    系列目录 最新比较闲,为了学习下Android的开发构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(1)-前言与,虽然有点没有目的的学习,但还是了解了Andro ...

  7. ASP.NET MVC5+EF6+EasyUI 后台管理系统(54)-工作流设计-所有流程监控

    系列目录 先补充一个平面化登陆页面代码,自己更换喜欢的颜色背景 @using Apps.Common; @{ Layout = null; } <!DOCTYPE html> <ht ...

  8. ASP.NET MVC5+EF6+EasyUI 后台管理系统(56)-插件---单文件上传与easyui使用fancybox

    系列目录 https://yunpan.cn/cZVeSJ33XSHKZ  访问密码 0fc2 今天整合lightbox插件Fancybox1.3.4,发现1.3.4版本太老了.而目前easyui 1 ...

  9. ASP.NET MVC5+EF6+EasyUI 后台管理系统(38)-Easyui-accordion+tree漂亮的菜单导航

    系列目录 本节主要知识点是easyui 的手风琴加树结构做菜单导航 有园友抱怨原来菜单非常难看,但是基于原有树形无限级别的设计,没有办法只能已树形展示 先来看原来的效果 改变后的效果,当然我已经做好了 ...

随机推荐

  1. nodejs进阶(4)—读取图片到页面

    我们先实现从指定路径读取图片然后输出到页面的功能. 先准备一张图片imgs/dog.jpg. file.js里面继续添加readImg方法,在这里注意读写的时候都需要声明'binary'.(file. ...

  2. 用php做注册审核

    做注册审核就像前面讲的注册登录一样,也是要连接数据库 首先在数据库内要做这样一张表: 表名为users表 里面的列名分别为用户名,密码,姓名,性别,生日,账户的状态,照片 然后就可以写代码了,要注册的 ...

  3. Azure Service Fabric 开发环境搭建

    微服务体系结构是一种将服务器应用程序构建为一组小型服务的方法,每个服务都按自己的进程运行,并通过 HTTP 和 WebSocket 等协议相互通信.每个微服务都在特定的界定上下文(每服务)中实现特定的 ...

  4. ExtJS 4.2 Grid组件的单元格合并

    ExtJS 4.2 Grid组件本身并没有提供单元格合并功能,需要自己实现这个功能. 目录 1. 原理 2. 多列合并 3. 代码与在线演示 1. 原理 1.1 HTML代码分析 首先创建一个Grid ...

  5. 【.net 深呼吸】跨应用程序域执行程序集

    应用程序域,你在网上可以查到它的定义,凡是概念性的东西,大伙儿只需要会搜索就行,内容看了就罢,不用去记忆,更不用去背,“名词解释”是大学考试里面最无聊最没水平的题型. 简单地说,应用程序域让你可以在一 ...

  6. 关于Android避免按钮重复点击事件

    最近测试人员测试我们的APP的时候,喜欢快速点击某个按钮,出现一个页面出现多次,测试人员能不能禁止这样.我自己点击了几下,确实存在这个问题,也感觉用户体验不太好.于是乎后来我搜了下加一个方法放在我们U ...

  7. 前端自动化构建工具gulp记录

    一.安装 1)安装nodejs 通过nodejs的npm安装gulp,插件也可以通过npm安装.windows系统是个.msi工具,只要一直下一步即可,软件会自动在写入环境变量中,这样就能在cmd命令 ...

  8. MySQL 系列(四)主从复制、备份恢复方案生产环境实战

    第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...

  9. MySQL 系列(二) 你不知道的数据库操作

    第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网 ...

  10. ASP.NET Core 中文文档 第四章 MVC(4.2)控制器操作的路由

    原文:Routing to Controller Actions 作者:Ryan Nowak.Rick Anderson 翻译:娄宇(Lyrics) 校对:何镇汐.姚阿勇(Dr.Yao) ASP.NE ...